Help with Dynamic Memory, Objects, Array of Pointers

  • Thread starter Thread starter Noah Pereira
  • Start date Start date
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::ostream& display(std::ostream& out) const;

//Returns object state
operator bool() const;

//Destructor
~MenuItem();

//make menu a friend
friend Menu;

//
friend std::ostream& operator<<(std::ostream& 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::ostream& display(std::ostream& os = std::cout) const;
int run(void) const;

};

std::ostream& operator<<(std::ostream& 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::ostream& MenuItem::display(std::ostream& out) const {
//Check for validitity
if (m_item) {
//Output item and a new line
out << m_item << std::endl;
}

return out;
}

std::ostream& operator<<(std::ostream& out, const MenuItem& mi) {
mi.display(out);

return out;
}

MenuItem::operator 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::operator=(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::operator=(const char* title) {
if (title) {
setTitle(title);
}
else {
m_title = nullptr;
}

return *this;
}

Menu& Menu::operator<<(const char* item) {
if (item) {
add(item);
}
else {
m_title = nullptr;
m_menuItem[MAX_NO_OF_ITEMS] = { nullptr };
m_menuCount = 0;
}

return *this;
}

Menu::operator int()const{
int rtn = run();
return rtn;
}

Menu::operator 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::ostream& Menu::display(std::ostream& 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...
 
Back
Top