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;
}
Related
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>>.
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!
I have a HashTable templated class and I'm having trouble deleting a dynamic array. (SLList = Singly Linked List)
My data members are:
SLList<Type>* m_ht;
unsigned int(*m_hFunction) (const Type &v);
unsigned int m_numOfBuckets;
In my constructor/assignment operator, I have the 'new' allocating the dynamic memory:
m_ht = new SLList<Type>[numOfBuckets];
My destructor:
m_ht = nullptr;
for (size_t i = 0; i < m_numOfBuckets; ++i) // idk if this for loop
delete m_ht[i]; // is correct
delete[] m_ht;
After closing the program and tracking the memory leaks, they are pointing for these both 'm_ht = new ...', and I don't know how to delete them properly.
Thank you!
You should move m_ht = nullptr; to the last line. Otherwise, the following delete and delete[] cannot get the address to release.
I have program which implements database of peoples and his companies. I have created dynamic array of pointer to class members instead of dynamic array of class members, cause copying is quicker with it.
I have version which works but valgrind shows mismatch delete in destructor (delete db)
CCompany** db;
~CCompanyIndex ( void )
{
for(unsigned i=0;i<len;i++)
{
/*cout<<"dealloc:"<<db[i]<<endl;*/
delete db[i];
}
delete db;
}
CCompanyIndex ( void )
{
max=1000;
len=0;
db=new CCompany*[max];
}
I use also to add
CCompany* newIt=new CCompany(oName,oAddr,cName,cAddr);
So I have tried following code which I consider correct previously
~CCompanyIndex ( void )
{
delete [] db;
}
But then all memory allocated by adding method is not deallocated.
The first sample is almost correct. You're deleting each element in a for loop, but then you attempt to delete the array.
for(unsigned i=0;i<len;i++) { delete db[i]; }
delete db;
It should instead be:
for(unsigned i=0;i<len;i++) { delete db[i]; }
delete[] db;
Whenever you use new ...[], you should be using delete[].
Also, don't forget the Rule of Three (or Five (or Zero)).
You are using the wrong delete. Do this:
CCompanyIndex::~CCompanyIndex()
{
for(unsigned i=0; i<len;i++) delete db[i];
delete [] db;
}
Note the delete [] call.
You need delete db[i] for each element but delete[] db for the array itself, so neither destructor was correct.
Arrays allocated with new Foo[n] must be deallocated with the array form, delete[], that's what valgrind means about mismatch new/delete
Suppose we have the following:
class StringClass
{
public:
...
void someProcessing( );
...
StringClass& operator=(const StringClass& rtSide);
...
private:
char *a;//Dynamic array for characters in the string
int capacity;//size of dynamic array a
int length;//Number of characters in a
};
StringClass& StringClass::operator=(const StringClass& rtSide)
{
capacity = rtSide.capacity;
length = rtSide.length;
delete [] a;
a = new char[capacity];
for (int i = 0; i < length; i++)
a[i] = rtSide.a[i];
return *this;
}
My question is: why does this implementation of overloading the assignment operator cause problems when we try to assign an object to itself like:
StringClass s;
s = s;
The textbook I'm reading (Absolute C++) says that after delete [] a; "The pointer s.a is then undefined. The assignment operator has corrupted the object s and this run of the program is probably ruined."
Why has the operator corrupted s? If we're reinitalizing s.a right after we delete it, why does this cause such a problem in the program that we have to redefine the function as:
StringClass& StringClass::operator=(const StringClass& rtSide)
{
if (this == &rtSide)
//if the right side is the same as the left side
{
return *this;
}
else
{
capacity = rtSide.capacity;
length = rtSide.length;
delete [] a;
a = new char[capacity];
for (int i = 0; i < length; i++)
a[i] = rtSide.a[i];
return *this;
}
}
If you are assigning an object to itself both a and rt.a point to the same string, so when you do delete [] a you are deleting both what a and rt.a point to; then you do reallocate it, but the data you were going to copy (on itself) in the loop has been lost in the delete.
In the loop now you will just copy whatever junk happens to be in the memory returned by new on itself.
By the way, even with the "safety net" of the self-assignment check that assignment operator isn't completely ok (for instance, it's not exception safe); the "safe" way to define the "big three" (copy constructor, assignment operator, destructor) is using the "copy and swap idiom".
If you self-assign, you free (delete) the string via the LHS argument before you copy it to the newly allocated space via the RHS argument. This is not a recipe for happiness; it is undefined behaviour and anything may happen. A crash is plausible; if you're really unlucky, it may appear to work.
Consider what the value of rtSide.a is when you're inside the broken operator=.
It's the same as this->a, the values you just clobbered. Accessing non-owned memory is undefined behavior, thus accessing this->a is undefined behavior (since you just freed it).
delete [] a;
a = new char[capacity];
for (int i = 0; i < length; i++)
a[i] = rtSide.a[i]; //Invalid when this->a == rtSide.a
//because rtSide.a is no longer owned by your program.
If you did actually want to do this, you would have to make a copy of a before deleting it:
char* ca;
if (this == &rtSide) {
ca = copy of rtSide.a or this->a;
} else {
ca = rtSide.a;
}
//Do your assigning and whatnot
if (this == &rtSide) {
delete[] ca;
}
Obviously it's much more efficient to just do nothing instead of making temporary copies of all of an instances own members. It's the same concept as doing int x = 5; int y = x; x = y;
It is because you've first deleted the pointer delete [] a;
and then later on trying to copy from the deleted location:
for (int i = 0; i < length; i++)
a[i] = rtSide.a[i]; //rtSide has already been deleted as 'this' and '&rtSide' are same.
Remember it is the same location you are trying to copy from, which you've already deleted.
Hence, the error!
The later code you posted fixes this problem by checking for self-assignment as a separate case.
delete [] a;
a = new char[capacity];
for (int i = 0; i < length; i++)
a[i] = rtSide.a[i];
That's why. Think of it like this:
You delete whatever a points to, then allocate a new chunk of memory. The new chunk of memory contains garbage which becomes your new data. Do not be confused by the loop that does a[i] = rtSide.a[i]; that only copies the garbage onto itself.
Remember, this and rtSide both lead you to the same object. When you modify the object using this the object that rtSide refers to is modified.