I have to write a code that gets a string and turns it into an object of a class. Everything is working as expected but I'm unable to deallocate the dynamically allocated 2d array of objects.
I know the issue is within the destructor and the Move assignment operator for the object, I keep getting SIGBRT and EXC_BAD_ACCESS errors when I try to run it.
Below is my Code for the constructor, destructor and move assignment/constructor
//CustomerOrder.cpp
CustomerOrder::CustomerOrder(std::string&
src):Name(src),Product(),ItemCount(),ItemList(),field_width(){
std::vector<ItemInfo> info;
std::string* tokens[] = { &Name, &Product };
Utilities utils;
size_t next_pos = -1;
bool more = true;
for (auto& i : tokens) {
if (!more) break;
*i = utils.extractToken(src, next_pos, more);
}
while (more){
info.push_back(utils.extractToken(src, next_pos, more));
}
if(!info.empty() && info.back().ItemName.empty()){
info.pop_back();
}
ItemCount = info.size();
ItemList = new ItemInfo*[ItemCount];
for (int i = 0; i < ItemCount; i++){
ItemList[i] = new ItemInfo(info.at(i).ItemName);
}
if (utils.getFieldWidth() > field_width){
field_width = utils.getFieldWidth();
}
}
CustomerOrder::~CustomerOrder(){
for(int i = 0; i<ItemCount;i++){
delete[] ItemList[i];
}
delete[] ItemList;
}
CustomerOrder::CustomerOrder(CustomerOrder&& src){
*this = std::move(src);
}
CustomerOrder& CustomerOrder::operator=(CustomerOrder&& src){
if(this!= &src){
delete [] ItemList;
Name = std::move(src.Name);
Product = std::move(src.Product);
ItemCount = std::move(src.ItemCount);
ItemList = std::move(src.ItemList);
src.ItemList = nullptr;
}
return *this;
}
And the ItemInfo struct
//ItemInfo struct
struct ItemInfo
{
std::string ItemName;
unsigned int SerialNumber;
bool FillState;
ItemInfo(std::string src) : ItemName(src), SerialNumber(0),
FillState(false) {};
};
You are combining "new" with "delete[]". If you use "new" use "delete" if you use "new[]" then use "delete[]" for the thing.
This is your problem there: "delete[] ItemList[i];" it should be "delete ItemList[i];" instead
This line of your code ItemList[i] = new ItemInfo(info.at(i).ItemName); doesn't allocate a dynamic array, yet this code in your destructor tries to delete it as thought it was a dynamic array.
for(int i = 0; i<ItemCount;i++){
delete[] ItemList[i];
}
A quick fix would to be to change delete[] to delete. However, it appears as though it would be much easier to simply allocate a single dynamic array. In other words, allocate ItemList as such ItemList = new ItemInfo[ItemCount]; Granted, you would have to change the type, but it makes more sense from what you posted.
Another possible issue is that in your destructor you don't check if the ItemList is a nullptr or actually allocated to anything. To which, your destructor could possibly try to access invalid data. Not only that, but your move operator deletes the ItemList without deleting the data inside of it.
You could make a function to free up the data in ItemList and then call that function from the destructor and move operator.
On a side note, why are you using dynamic 2D arrays when it appears that you know how to use vectors? A vector would handle all of this in a much simpler fashion. For example, the type would be std::vector<std::vector<ItemInfo>>.
Related
I'm new to C++ and try to understand how to create and use a class in C++.
For this I have the following code:
class MyClass
{
public:
MyClass()
{
_num = 0;
_name = "";
}
MyClass(MyClass* pMyClass)
{
_num = pMyClass->_num;
_name = pMyClass->_name;
}
void PrintValues() { std::cout << _name << ":" << _num << std::endl; }
void SetValues(int number, std::string name)
{
_num = number;
_name = name;
}
private:
int _num;
std::string _name;
};
int main()
{
std::vector<MyClass*> myClassArray;
MyClass myLocalObject = new MyClass();
for (int i = 0; i < 3; i++)
{
myLocalObject.SetValues(i, "test");
myClassArray.push_back(new MyClass(myLocalObject));
}
myClassArray[1]->PrintValues();
// use myClassArray further
}
I get a similar example from the internet and try to understand it.
My intentions is to populate myClassArray with new class objects.
If I compile the code above using VisualStudio 2022 I get no errors, but I'm not sure it doesn't produce memory leaks or if there is a faster and simple approach.
Especially I do not understand the following line:
MyClass myLocalObject = new MyClass();
myLocalObject is created on the stack but is initialized with a heap value (because of the new). If new operator is used where should delete must apply?
Thank you for any suggestions!
You have a memory leak at MyClass myLocalObject = new MyClass();, since the dynamically-allocated object is used to converting-construct the new myLocalObject (this was almost but not quite a copy constructor) and then the pointer is lost.
You also didn't show the code using the vector, but if it doesn't delete the pointers inside, you will have more memory leaks.
There's no reason to have an almost-copy-constructor; the compiler has provided you with a better real copy-constructor.
The faster and simpler approach is to recognize that this code doesn't need pointers at all.
class MyClass
{
public:
MyClass()
: _num(), _name() // initialize is better than assignment
{
//_num = 0;
//_name = "";
}
// compiler provides a copy constructor taking const MyClass&
//MyClass(MyClass* pMyClass)
//{
// _num = pMyClass->_num;
// _name = pMyClass->_name;
//}
void PrintValues() { std::cout << _name << ":" << _num << std::endl; }
void SetValues(int number, std::string name)
{
_num = number;
_name = name;
}
private:
int _num;
std::string _name;
};
int main()
{
std::vector<MyClass> myClassArray; // not a pointer
MyClass myLocalObject; // = new MyClass(); // why copy a default instance when you can just default initialize?
for (int i = 0; i < 3; i++)
{
myLocalObject.SetValues(i, "test"); // works just as before
myClassArray.push_back(/*new MyClass*/(myLocalObject)); // don't need a pointer, vector knows how to copy objects
// also, this was using the "real" copy-constructor, not the conversion from pointer
}
myClassArray[1].PrintValues(); // instead of ->
// use myClassArray further
}
for cases where a pointer is necessary, for example polymorphism, use a smart pointer:
std::vector<std::unique_ptr<MyClass>> myClassArray; // smart pointer
myClassArray.push_back(make_unique<MyDerivedClass>(stuff));
std::unique_ptr will automatically free the object when it is removed from the vector (unless you explicitly move it out), avoiding the need to remember to delete.
There are basically 2 ways to instantiate objects of classes.
Dynamic allocation (on heap)
MyClass* myLocalObject = new MyClass(); // dynamically allocates memory and assigns memory address to myLocalObject
Example for your loop:
class MyClass
{
private:
int _num;
std::string _name;
public:
// let's add an additional constuctor having default values
// that makes it easier later on
// if parameters are passed, they are used, or the defalt values, if not
// can call it like MyClass(), MyClass(123), or MyClass(456,"hello")
// you might want to pass larger data as reference, to avoid copying it
MyClass(int num=0, std::string name = "some default text")
: _num(num), _name(name)
{}
};
std::vector<MyClass*> myClassArray; // your array of pointers
for (int i = 0; i < 3; i++)
myClassArray.push_back(new MyClass(i, "test"));
// delete
for (auto& pointerToElement : myClassArray) // get a reference to each element (which is a pointer)
delete pointerToElement; // delete element (call's destructor if defined)
In that case you must delete myLocalObject; or you get a memory leak.
Instead of dealing with raw pointers, especially when new to C++, I recommend to use smart pointers, that deal with memory management for you.
Automatic allocation (on stack when possible)
MyClass myLocalObject = MyClass(); // automatically allocates memory and creates myLocalObject
This happens usually on stack (if possible). That's much faster and you don't have to deal with dynamic memory management
Example for your loop:
std::vector<MyClass> myClassArray; // now "containg" the memory of objects itself
for (int i = 0; i < 3; i++)
{
myClassArray.emplace_back(i, "test"); // we use emplace_back instead to construct instances of type MyClass directly into the array
}
// no deletion required here
// destructors of each element will be called (if defined) when myClassArray is deleted automatically when out of scope
There are other ways, like dynamic stack allocation and other black magic, but recommend to focus on "the standard".
In case of dealing with large amounts of data, you might want to use std::vector::reserve. In combination with automatic/stack allocation that helps to speed up a lot by limiting memory allocations to 1 at all instead of 1 per element.
Hope that helps :-)
I am writing code for a backtracking approach to a Traveling Salesman type of problem. So at each point i will recurse for rest of the un-visited points.
I could not use any library/functions other than cout, cin, new and delete (so no vector). So for the problem i want to keep a track of what all points i have visited till now. I am using a dynamic boolean array for this. So i want to pass the dynamic array to a function as value to keep track of this.
This is what i have tried till now.
I tried to wrap the array in a struct, but the memory dealocation (delete) is giving error (Segmentation fault)
typedef struct Barray{
bool* a;
int size;
Barray(int size) { a = new bool[size]; this->size = size; }
Barray(const Barray& in) {
if(a) delete[] a; // error
a = new bool[in.size];
this->size = in.size;
for (int i = 0; i < in.size; i++)
a[i] = in.a[i];
}
~Barray() { delete[] a; } // error
}barray;
This is my recursive function call
void find_mindist(barray visited, int dist_now, int cur_p) {
if (base condition)
{return ;}
for (int i = 0; i < n; i++) {
if (visited.a[i]) continue;
barray tdist = visited;
tdist.a[i] = true;
int ndist = dist_now + dist(points[cur_p], points[i]);
find_mindist(tdist, ndist, i);
}
return ;
}
So my questions are -
how can i pass a dynamic array to a function as value?
Why is the delete above giving error?
First of all, the recommended approach for a local visited information is not the endless copying of the whole visited collection, but a mark->recurse->unmark approach. So whatever you do, please keep a single boolean array for the visited information and update its content to your needs.
The other problems occur because you try to delete an uninitialized pointer in the copy constructor. Also, the assignment operator should be overloaded as well to avoid unpleasent surprises. But non of this really matters if you don't copy your visited information anymore.
The problem this is a copy constructor. As such, on entry, a is uninitialized (so contains garbage), so the delete is invalid.
Barray(const Barray& in) {
if(a) delete[] a; // error
a = new bool[in.size];
this->size = in.size;
for (int i = 0; i < in.size; i++)
a[i] = in.a[i];
}
Just remove the delete line. Also, prefer to initialize members, rather
than assign them, so:
Barray(const Barray& in)
: a(new bool[in.size])
, size(in.size) {
for (int i = 0; i < in.size; i++)
a[i] = in.a[i];
}
Also, remember the Rule of Three. You need an copy assignment operator. The simplest is:
Barry& operator=(const Barray& in) = delete;
which just forces a compilation error if you try to use it! Better is:
Barry& operator=(const Barray in) { // **NOTE** pass by value!
std::swap(this.a, in.a);
std::swap(this.size, in.size);
}
This version provides the strong exception guarantee. You aren't allowed to use std::swap, so you'll either have to write your own, or write it out by hand (you choose).
Finally, if you ever find yourself returning a Barray, you should write a move constructor:
Barray(Barray &&in)
: a(in.a)
, size(in.size) {
in.a = nullptr;
}
This can save a lot of copying!
In my program I have to overload the = operator. The overloading function looks like:
Polygon &Polygon::operator=(const Polygon &source)
{
this->capacity = source.capacity;
this->index = source.index;
this->vertex = new Vertex[source.capacity];
for(int i = 0; i < source.capacity; i++)
{
this->vertex[i] = source.vertex[i];
}
return *this;
}
But if there is one thing I have learned is that I am responsible of deleting things i create with the "new" keyword.
So before returning I tried with:
delete vertex;
But that didn't work since it deletes the object which I just copied to.
So I tried with:
delete source.vertex;
Which crashed my program during runtime.
I have tried alot of other ways also, but they are just tries with thought behind.
I would really like your help, not only giving me what I should write, but how I should think in these scenarios.
Before this statement
this->vertex = new Vertex[source.capacity];
insert statement
delete [] this->vertex;
Also the operator must look the following way
Polygon &Polygon::operator=(const Polygon &source)
{
if ( this != &source )
{
this->capacity = source.capacity;
//...
}
return *this;
}
The program probably crashed because you used delete to delete a pointer created with operator new[] (not operator new). These are two different things. You always have to match the two, using delete[] with new[]:
int *p = new int;
delete p;
int *q = new int[10];
delete [] q;
You can't delete vertex there because the object is still referencing it. The destructor for Polygon should be responsible for deleting the Vertex objects it creates:
~Polygon::Polygon()
{
if (vertex)
delete[] vertex;
}
vector<ClassX> xVec;
if (inputFile.peek() == '$')
{
classX classXInstance; //<==================== local instantiation
readFileElements(classXInstance);//<== pass by reference
if(classXInstance.validate())
{
xVec.push_back(classXInstance);///<=============== added here
}
/// destructor of the local copy is called here
}
I get a core dump, tried to debug, however I get so much junk messages with gdb, all I can see that the vector got corrupted, NOT sure if it because the destructor is called is a reason??
EDIT:
my class look like this
class ClassX
{
public:
ClassX() { numberOfX=0; ppXX = NULL; };
~ClassX();
void validate();
char **setX(const vector<string>& Xss);
inline char **getX() {return ppXX;};
private:
int numberOfX;
char **ppXX;
};
and it contains a destructor as follow
ClassX::~ClassX()
{
if (ppXX != NULL)
{
for(int i=0; i < numberOfXX; i++)
{
if (ppXX[i] != NULL)
{
delete [] ppXX[i];
ppXX[i] = NULL;
}
}
// Free array of pointers.
delete [] ppXX;
ppXX = NULL;
}
}
the setX allocate all memory necessary
validate give me a printout of the ppXX[i] and return true if number of elements matches the size of string vector
A copy of classXinstance is stored into xVec, with a pointer ppXX to a region in memory. Now you have two objects pointing to the same region. A moment later, classXinstance is destroyed, so the region is subject to delete. The element within xVec is now pointing to invalid memory.
The best option is to use std::Vector<std::string> instead of char **ppXX; a vector of strings takes care of references and allocation so you don't need to worry about proper construction/copy/destruction.
#include <QList>
class MyType{
//This has some data in it....
};
QList<MyType> f()
{
QList<MyType> list;
for(int i = 0; i<10; i++ )
{
MyType* item = new MyType();
list << *item;
}
return list;
}
QList<MyType> temp_var = f();
When temp_var goes out of the scope and destroys, what happens to the items that we created and add to this list?
Is there going to be any memory leaks?
Thank you.
Yes, there will be a memory leak. As a general rule, you must have one delete for each new in your program.
In your specific case, the faulty logic happens much earlier than temp_var's destruction. You allocate the items, and then store a copy of those items in the list. You should immediately destroy the original, no-longer-useful items.
Your for loop could be :
for(int i = 0; i<10; i++ )
{
MyType* item = new MyType(); // get me an item.
list << *item; // put copy of item in list
delete item; // destroy my item
}
When expressed that way, it is obvious that we shouldn't use new at all!
for(int i = 0; i < 10; i++)
{
MyType item;
list << item;
}
This version won't leak, assuming that MyType doesn't have any memory-management bugs of its own.
EDIT: As an aside, had your program been:
QList<MyType*> f() // List of POINTERS
{
QList<MyType*> list;
for(int i = 0; i<10; i++ )
{
MyType* item = new MyType();
list << item; // Storing a POINTER
}
return list;
}
Then, yes, you would have had precisely the memory leak you expected. QList does not automatically provide delete on pointer types.
I don't see any point of using new in your code, as you're not storing the pointers in the list, rather copies of the object created with new, and you're not deleteing it. So yeah, there is memory-leak in the function itself.
Seeing that QList is not a list of pointers, I can say that you shouldn't use new in your code:
QList<MyType> f()
{
QList<MyType> list; //note : its not a list of MyType*
for(int i = 0; i<10; i++ )
{
MyType item; //automatic variable
list << item;
}
return list;
}
When a QList gets destroyed / goes out of scope, it destroys its content with it. In your case, the content is made of copies of your objects (built from the implicit copy-constructor), not the objects themselves. The memory will leak in each iteration of the for-loop since the original object created by new MyType() will lose its pointer, but will remain allocated.
There certainly will be a leak if it you don't delete all of those items you created with new MyType()!
In the destructor for QList you need to go through the list and call delete on each of those items.