N
Noah Pereira
Guest
Hi, Ill try and explain my problem the best i can.
I have a a module Menu, that holds two Classes, Menu and MenuItem, Menu has a dynamic array of pointers that holds MenuItems with a max size.
I am having memory leaks at the lines highlighted in the code blocks, I'm not entirely new to dynamic memory, but I am new to having multiple objects with memory to be managed.
The purpose of the module is to be able to add and remove MenuItems which can create a custom and interactive menu. Here are the Moduless
Menu.h
#include <cstring>
#include <iostream>
#include <iomanip>
namespace sdds {
//Forward declaration of class Menu
class Menu;
class MenuItem {
private:
//Item name
char* m_item;
//Default constructor
MenuItem();
//Custom constructor
MenuItem(const char* item);
//Copy Constructor is privatized so that no copy can be done (no implementation aswell)
MenuItem(const MenuItem&);
//overload equal operator to private
MenuItem& operator=(const MenuItem&);
//Displays its content
std:stream& display(std:stream& out) const;
//Returns object state
operator bool() const;
//Destructor
~MenuItem();
//make menu a friend
friend Menu;
//
friend std:stream& operator<<(std:stream& out, const MenuItem& mi);
};
//max no of menu items
const int MAX_NO_OF_ITEMS = 10;
class Menu {
private:
char* m_title; //Holds title
MenuItem* m_menuItem[MAX_NO_OF_ITEMS + 1]; //Holds array of pointers to items
int m_menuCount; //Holds menuItems count
int m_indentation;
void setTitle(const char* title);
public:
//Class Constructors and Destructors
Menu();
Menu(const char* title, int indent = 0);
~Menu();
//Operator Overloads
Menu& operator=(const Menu& menu);
Menu& operator=(const char* title);
Menu& operator<<(const char* item);
operator int() const;
operator bool() const;
//Member functions
bool isEmpty(void) const;
void add(const char* item);
std:stream& display(std:stream& os = std::cout) const;
int run(void) const;
};
std:stream& operator<<(std:stream& out, MenuItem& mi);
}
Menu.cpp
#include "Menu.h"
#include "Utils.h"
namespace sdds {
MenuItem::MenuItem() {
m_item = nullptr;
}
MenuItem::MenuItem(const char* item) {
if (item) {
m_item = nullptr;
//Create variables
char buf;
int i = 0;
//Calculate length of char length
do
{
buf = item;
i++;
} while (buf != '\0');
//Allocate memory for m_item
m_item = new char;
//Copy item to m_item
strncpy(m_item, item, i);
m_item[i - 1] = '\0';
} else {
m_item = nullptr;
}
}
std:stream& MenuItem::display(std:stream& out) const {
//Check for validitity
if (m_item) {
//Output item and a new line
out << m_item << std::endl;
}
return out;
}
std:stream& operator<<(std:stream& out, const MenuItem& mi) {
mi.display(out);
return out;
}
MenuItem:perator bool() const {
//Return if object has a item
return m_item ? 1 : 0;
}
MenuItem::~MenuItem() {
//Delete m_item
std::cout << "Deleting Menu Item";
delete [] m_item;
}
//Menu Class
//
//
void Menu::setTitle(const char* title) {
if (!isEmpty()) {
delete[] m_title;
m_title = nullptr;
}
//Create variables
char buf;
int i = 0;
//Calculate length of char length
do
{
buf = title;
i++;
} while (buf != '\0');
//Allocate memory for m_title
m_title = new char; <<<<<<--------------Memory Leak
//Copy item to m_title
strncpy(m_title, title, i);
m_title[i - 1] = '\0';
}
Menu::Menu() {
m_title = nullptr;
m_menuItem[MAX_NO_OF_ITEMS] = { nullptr };
m_menuCount = 0;
m_indentation = 0;
}
Menu::Menu(const char* title, int indent) {
if (title) {
//Initialize m_title
setTitle(title);
//Initialize m_indentation
if (indent >= 0) {
m_indentation = indent;
}
//Intiialize other values
m_menuItem[MAX_NO_OF_ITEMS] = { nullptr };
m_menuCount = 0;
}
else {
//Initialize Values
m_title = nullptr;
m_menuItem[MAX_NO_OF_ITEMS] = { nullptr };
m_menuCount = 0;
m_indentation = 0;
}
}
Menu::~Menu() {
for (int i = 0; i < m_menuCount; i++) {
delete [] m_menuItem->m_item;
m_menuItem = nullptr;
}
delete[] m_title;
m_title = nullptr;
m_menuCount = 0;
}
Menu& Menu:perator=(const Menu& menu) {
if (!menu.isEmpty()) {
//Shallow Copy
m_indentation = menu.m_indentation;
m_menuCount = 0;
//Deep copy for resources
setTitle(menu.m_title);
for (int i = 0; i < menu.m_menuCount; i++) {
add(menu.m_menuItem->m_item);
}
}
else {
m_title = nullptr;
m_menuItem[MAX_NO_OF_ITEMS] = { nullptr };
m_menuCount = 0;
m_indentation = 0;
}
return *this;
}
Menu& Menu:perator=(const char* title) {
if (title) {
setTitle(title);
}
else {
m_title = nullptr;
}
return *this;
}
Menu& Menu:perator<<(const char* item) {
if (item) {
add(item);
}
else {
m_title = nullptr;
m_menuItem[MAX_NO_OF_ITEMS] = { nullptr };
m_menuCount = 0;
}
return *this;
}
Menu:perator int()const{
int rtn = run();
return rtn;
}
Menu:perator bool() const {
return !isEmpty();
}
bool Menu::isEmpty(void) const {
return (m_title != nullptr) ? 0 : 1;
}
void Menu::add(const char* item) {
if (item) {
if (m_menuCount < MAX_NO_OF_ITEMS && !isEmpty()) {
MenuItem* temp = new MenuItem(item); <<<<---------(Memory Leak)
m_menuItem[m_menuCount] = temp;
m_menuCount++;
}
}
else {
m_title = nullptr;
m_menuItem[MAX_NO_OF_ITEMS] = { nullptr };
m_menuCount = 0;
m_indentation = 0;
}
}
std:stream& Menu::display(std:stream& os) const {
if (*this) {
if (m_menuCount == 0) {
//Print no items to display
std::cout << "No Items to display!" << std::endl;
}
//Print Title
std::cout.width(m_indentation * 4);
std::cout << m_title << std::endl;
//Print Options
for (int i = 0; i < m_menuCount; i++) {
std::cout.width(m_indentation * 4);
std::cout << i + 1 << "- ";
m_menuItem->display(std::cout);
}
//Print dialouge
std::cout.width(m_indentation * 4);
std::cout << "> ";
} else {
std::cout << "Invalid Menu!" << std::endl;
}
return os;
}
int Menu::run(void) const {
int o = 0;
if (*this && m_menuCount > 0) {
std::cin.clear();
display();
o = grabIntInRange(1, m_menuCount);
}
else {
std::cout << "Invalid Menu!" << std::endl;
}
return o;
}
The second memory leak inside the add() function confuses me, the first one is easier to understand but confuses me because I am making sure their is no m_title memory still alive, I am checking right before allocating?
Any Help would be amazing, never hurts to learn!
Thanks Guys
Continue reading...
I have a a module Menu, that holds two Classes, Menu and MenuItem, Menu has a dynamic array of pointers that holds MenuItems with a max size.
I am having memory leaks at the lines highlighted in the code blocks, I'm not entirely new to dynamic memory, but I am new to having multiple objects with memory to be managed.
The purpose of the module is to be able to add and remove MenuItems which can create a custom and interactive menu. Here are the Moduless
Menu.h
#include <cstring>
#include <iostream>
#include <iomanip>
namespace sdds {
//Forward declaration of class Menu
class Menu;
class MenuItem {
private:
//Item name
char* m_item;
//Default constructor
MenuItem();
//Custom constructor
MenuItem(const char* item);
//Copy Constructor is privatized so that no copy can be done (no implementation aswell)
MenuItem(const MenuItem&);
//overload equal operator to private
MenuItem& operator=(const MenuItem&);
//Displays its content
std:stream& display(std:stream& out) const;
//Returns object state
operator bool() const;
//Destructor
~MenuItem();
//make menu a friend
friend Menu;
//
friend std:stream& operator<<(std:stream& out, const MenuItem& mi);
};
//max no of menu items
const int MAX_NO_OF_ITEMS = 10;
class Menu {
private:
char* m_title; //Holds title
MenuItem* m_menuItem[MAX_NO_OF_ITEMS + 1]; //Holds array of pointers to items
int m_menuCount; //Holds menuItems count
int m_indentation;
void setTitle(const char* title);
public:
//Class Constructors and Destructors
Menu();
Menu(const char* title, int indent = 0);
~Menu();
//Operator Overloads
Menu& operator=(const Menu& menu);
Menu& operator=(const char* title);
Menu& operator<<(const char* item);
operator int() const;
operator bool() const;
//Member functions
bool isEmpty(void) const;
void add(const char* item);
std:stream& display(std:stream& os = std::cout) const;
int run(void) const;
};
std:stream& operator<<(std:stream& out, MenuItem& mi);
}
Menu.cpp
#include "Menu.h"
#include "Utils.h"
namespace sdds {
MenuItem::MenuItem() {
m_item = nullptr;
}
MenuItem::MenuItem(const char* item) {
if (item) {
m_item = nullptr;
//Create variables
char buf;
int i = 0;
//Calculate length of char length
do
{
buf = item;
i++;
} while (buf != '\0');
//Allocate memory for m_item
m_item = new char;
//Copy item to m_item
strncpy(m_item, item, i);
m_item[i - 1] = '\0';
} else {
m_item = nullptr;
}
}
std:stream& MenuItem::display(std:stream& out) const {
//Check for validitity
if (m_item) {
//Output item and a new line
out << m_item << std::endl;
}
return out;
}
std:stream& operator<<(std:stream& out, const MenuItem& mi) {
mi.display(out);
return out;
}
MenuItem:perator bool() const {
//Return if object has a item
return m_item ? 1 : 0;
}
MenuItem::~MenuItem() {
//Delete m_item
std::cout << "Deleting Menu Item";
delete [] m_item;
}
//Menu Class
//
//
void Menu::setTitle(const char* title) {
if (!isEmpty()) {
delete[] m_title;
m_title = nullptr;
}
//Create variables
char buf;
int i = 0;
//Calculate length of char length
do
{
buf = title;
i++;
} while (buf != '\0');
//Allocate memory for m_title
m_title = new char; <<<<<<--------------Memory Leak
//Copy item to m_title
strncpy(m_title, title, i);
m_title[i - 1] = '\0';
}
Menu::Menu() {
m_title = nullptr;
m_menuItem[MAX_NO_OF_ITEMS] = { nullptr };
m_menuCount = 0;
m_indentation = 0;
}
Menu::Menu(const char* title, int indent) {
if (title) {
//Initialize m_title
setTitle(title);
//Initialize m_indentation
if (indent >= 0) {
m_indentation = indent;
}
//Intiialize other values
m_menuItem[MAX_NO_OF_ITEMS] = { nullptr };
m_menuCount = 0;
}
else {
//Initialize Values
m_title = nullptr;
m_menuItem[MAX_NO_OF_ITEMS] = { nullptr };
m_menuCount = 0;
m_indentation = 0;
}
}
Menu::~Menu() {
for (int i = 0; i < m_menuCount; i++) {
delete [] m_menuItem->m_item;
m_menuItem = nullptr;
}
delete[] m_title;
m_title = nullptr;
m_menuCount = 0;
}
Menu& Menu:perator=(const Menu& menu) {
if (!menu.isEmpty()) {
//Shallow Copy
m_indentation = menu.m_indentation;
m_menuCount = 0;
//Deep copy for resources
setTitle(menu.m_title);
for (int i = 0; i < menu.m_menuCount; i++) {
add(menu.m_menuItem->m_item);
}
}
else {
m_title = nullptr;
m_menuItem[MAX_NO_OF_ITEMS] = { nullptr };
m_menuCount = 0;
m_indentation = 0;
}
return *this;
}
Menu& Menu:perator=(const char* title) {
if (title) {
setTitle(title);
}
else {
m_title = nullptr;
}
return *this;
}
Menu& Menu:perator<<(const char* item) {
if (item) {
add(item);
}
else {
m_title = nullptr;
m_menuItem[MAX_NO_OF_ITEMS] = { nullptr };
m_menuCount = 0;
}
return *this;
}
Menu:perator int()const{
int rtn = run();
return rtn;
}
Menu:perator bool() const {
return !isEmpty();
}
bool Menu::isEmpty(void) const {
return (m_title != nullptr) ? 0 : 1;
}
void Menu::add(const char* item) {
if (item) {
if (m_menuCount < MAX_NO_OF_ITEMS && !isEmpty()) {
MenuItem* temp = new MenuItem(item); <<<<---------(Memory Leak)
m_menuItem[m_menuCount] = temp;
m_menuCount++;
}
}
else {
m_title = nullptr;
m_menuItem[MAX_NO_OF_ITEMS] = { nullptr };
m_menuCount = 0;
m_indentation = 0;
}
}
std:stream& Menu::display(std:stream& os) const {
if (*this) {
if (m_menuCount == 0) {
//Print no items to display
std::cout << "No Items to display!" << std::endl;
}
//Print Title
std::cout.width(m_indentation * 4);
std::cout << m_title << std::endl;
//Print Options
for (int i = 0; i < m_menuCount; i++) {
std::cout.width(m_indentation * 4);
std::cout << i + 1 << "- ";
m_menuItem->display(std::cout);
}
//Print dialouge
std::cout.width(m_indentation * 4);
std::cout << "> ";
} else {
std::cout << "Invalid Menu!" << std::endl;
}
return os;
}
int Menu::run(void) const {
int o = 0;
if (*this && m_menuCount > 0) {
std::cin.clear();
display();
o = grabIntInRange(1, m_menuCount);
}
else {
std::cout << "Invalid Menu!" << std::endl;
}
return o;
}
The second memory leak inside the add() function confuses me, the first one is easier to understand but confuses me because I am making sure their is no m_title memory still alive, I am checking right before allocating?
Any Help would be amazing, never hurts to learn!
Thanks Guys
Continue reading...