This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
What is The Rule of Three?
People say that if you need a destructor then you actually need an overloaded operator=
struct longlife{ };
class z
{
z(){};
~z(){ for( auto it=hold.begin();it!=hold.end() ++it ) delete(*it); };
vector<longlife*> hold;
};
Suppose all pointer inserted on hold were newheap allocated, why is anything else besides a deconstructor needed on this example?
By anything else I mean things like,
z& operator=( const z&ref )
{
hold = ref.hold;
return *this;
}
Would:
z a;
a.hold.push_back( heap_item );
z a2;
a2 = a;
Cause memory leak? Sometimes it's hard to understand why the rule of three is a rule
Not only is the assignment operator required, you also need to implement a copy constructor. Otherwise the compiler will provide default implementations that will result in both copies (after assignment / copy construction) containing pointers to the same longlife instances. Destructors of both copies will then delete these instances leading to undefined behavior.
z a;
a.hold.push_back( heap_item );
z a2;
a2 = a;
Both a.hold[0] and a2.hold[0] contain a pointer to the same heap_item; thus causing double deletion during destruction.
The easy way to avoid having to implement the assignment operator and copy constructor is to use a smart pointer to hold the longlife instances in the vector.
std::vector<std::unique_ptr<longlife>> hold;
Now there's no need to even write a destructor for your class.
For C++03, your options are to use std::tr1::shared_ptr (or boost::shared_ptr) instead of unique_ptr or use boost::ptr_vector (of course, this is also an option for C++11) instead of std::vector.
Because without an assignment operator and a copy constructor you may end up with multiple hold vectors pointing to the same heap item, resulting in undefined behavior upon destruction:
z firstZ;
if (somethingIsTrue) {
z otherZ = firstZ;
// play with otherZ...
// now otherZ gets destructed, along with longlife's of the firstZ
}
// now it's time to destroy the firstZ, but its longlife's are long gone!
Of course you would not have this problem had you used a vector of objects or a vector of "smart pointers", rather than a vector of "plain old" pointers.
See the Rule of Three for more information.
It would cause a double delete (and crash) on the destructor of a or a2 (whichever was destroyed second) because the default assignment constructor would do a binary copy of the memory state of hold. So each object a and a2 would end up deleting the exact same memory.
From your comments:
#Xeo, I understand what the rule of three is, the question is mostly
why is it a rule
Consider what happens here:
z& operator=( const z&ref )
{
hold = ref.hold;
return *this;
}
Lets say you have an instance of z:
z myz;
myz.a.hold.push_back( new long_life );
...and then you create a copy of this myz:
z my_other_z;
// ...
my_other_z = myz;
The operator= implementation you have provided above simply copies the contents of the vector. If the vector has pointers, it doesn't make copies of whatever's being pointed to -- it just makes a literal copy of the pointer itself.
So after operator= returns, you will have 2 instances of z that have pointers pointing to the same thing. When the first of those zs is destructed, it will delete the pointer:
~z(){ for( auto it=hold.begin();it!=hold.end() ++it ) delete(*it); };
When it comes time for the second z to be destroyed, it will try to delete the same pointer a second time. This results in Undefined Behavior.
The solution to this problem is to make deep copies when you assign or copy objects that maintain resources that need to be allocated and deleted. That means providing an assignment operator and a copy constructor.
That is why the rule of three is a RULE.
EDIT:
As others have mentioned, this is all better avoided altogether by using value semantics and RAII. Reengineering your objects to use the Rule of Zero, as others have called it, is a much better approach.
Actually there will be a double free here, not a memory leak.
STL containers store objects, not references. In your case object is a pointer. Pointers are simply copied. Your line a2 = a; will duplicate pointer in the vector. After that each destructor will release the pointer.
Double free is much more dangerous than the memory leak. It causes nasty undefined behavior:
MyStruct *p1 = new MyStruct();
delete p1;
.... do something, wait, etc.
delete p1;
at the same time on the other thread:
MyOptherStruct *p2 = new MyOtherStruct();
.... do something, wait, etc.
p2->function();
It may turn out that memory allocator will assign to p2 exactly the same value that was used for p1, because it is free after the first call to delete p1. A while later second delete p1 will also go fine because allocator thinks that this is a legitimate pointer that was given out for p2. The problem will appear only at p2->function();. Looking at the code of thread 2 it is absolutely impossible to understand what went wrong and why. This is extremely difficult to debug, especially if the system is big.
Related
This question already has answers here:
Is it worth setting pointers to NULL in a destructor?
(12 answers)
Closed 7 years ago.
I saw a common practice of deleting the pointer amd making it null in destructor even if no memory is allocated to pointer on heap. Consider below C++ code:
dummy.h
class dummy
{
int* a;
}
dummy.cpp
dummy::dummy():a(NULL)
{ cout<<Inside Const"; }
dummy::~dummy()
{
if(a!=NULL)
{
delete a;
a = NULL;
}
}
bool func()
{
a = func1();
}
In above code although memory to a is not allocated on heap, even then it is deleted. It should not lead to memory leak?
Making it null is completely pointless, since it's about to be destroyed.
Your code isn't deleting it if it's null, due to the if (a!=NULL). However, that's also pointless: applying delete to a null pointer will simply do nothing, so you can reduce the destructor to an unconditional delete a; (assuming that you know that it's either null, or points to an object created with new).
You do need to make sure your class either isn't copyable, or has valid copy semantics, per the Rule of Three; otherwise, copying the object will lead to deleting the same memory twice, which is not allowed.
Better still, stop juggling pointers, and use smart pointers, containers and other RAII types to make life much simpler.
You should not call delete on a pointer that points to an object that isn't heap allocated object, ever. If you do, the program may ignore that line. Or it may erase your hard drive. Or it may ignore that line on your computer, and after you give the program to a friend it erases their hard drive. Don't do it.
Related: your class is missing the copy constructor, and copy assignment which are critical when you have a pointer that manages memory. Alternatively, replace the int* member with a unique_ptr<int> member, which manages construction and movement for you.
This question already has answers here:
Double free or corruption after queue::push
(6 answers)
What is The Rule of Three?
(8 answers)
Closed 9 years ago.
Use example in link, but change to use char * and vector:
#include <vector>
using namespace std;
class Test{
char *myArray;
public:
Test(){
myArray = new char[10];
}
~Test(){
delete[] myArray;
}
};
int main(){
vector<Test> q; // line 1
Test t; // line 2
q.push_back(t);
}
It will cause double free or corruption error. However, if run line 2 before line 1, like:
Test t;
vector<Test> q;
Then it runs ok. Why is that?
Tested on Xubuntu 12.04 g++ 4.6.3.
Updated:
It's not duplicate question. I understand a copy constructor and an assignment operator are needed (it's already answered in the above link where the sample code is from). However, using int * or queue like that in the original link, but swapping line 1 and line 2, there is still error. Only using char *, and vector and swapping line 1 and line 2 will not cause error. My question is why is this particular case? Can anyone check it in your platform?
Your type manages resources (a dynamically allocated array) but does not implement the rule of three. When you do this:
q.push_back(t);
q makes a copy of t, which it owns. So now you have two copies of an object referring to the same data, and attempting to call delete in it.
You need to implement a copy constructor and an assignment operator. Or use a class that manages its own resources, such as std::string or std::vector.
Calling delete[] on an already deleted array is undefined behaviour (UB). This means that sometimes your program might seem to work. You cannot rely on a program with undefined behaviour to do anything. Swapping lines 1 and 2 inverts the order in which t and q get destroyed. This seems to yield a different result on your platform, but both are UB.
C++ automatically makes a shallow copy of your Test object when you push it to the vector. When the vector goes out of scope and is destructed, the myArray pointer is delete[]d. Then, when Test goes out of scope, the same pointer is delete[]d again.
You should specify a copy constructor and make a deep copy of the object. Along with a new array.
Overloading assignment operator (explained in the same link as above) is also strongly suggested.
Rule of three (http://en.wikipedia.org/wiki/Rule_of_three_%28C%2B%2B_programming%29). There is likely an assignment going on that you don't see between two Test objects, so the old pointer from one object is being naively assigned to the new object.
Because you need a copy constructor.
push_back copies the argument and as you haven't provided a copy constructor, there's a default one, making a shallow copy (copy just the pointer, without the content *)
So, you need to define a
Test( const Test& other )
{
// ...
}
Test& operator=( const Test& other ) // just in case
{
// ...
}
and make a deep copy, manually copying the char* buffer.
*) which leads to double deletion - once from the t's destructor, once from the q's destructor (which calls the destructors of all elements in the vector)
This is because the Test objects are automatically created and deleted when managed by vector and when they are inserted by push_back. Imagine that when new elements are added to the vector, more space is needed and allocated and the existing elements are copied to new addresses. Which means they are are deleted and their dynamic memory deallocated. To be able to overcome this, define copy constructor for your class that will make a deep copy of the object. Or use smart pointers such as unique_ptr or shared_ptr (from boost or C++11).
This question already has answers here:
What is The Rule of Three?
(8 answers)
Closed 8 years ago.
I'm having trouble figuring out a way to return an object (declared locally within the function) which has dynamic memory attached to it. The problem is the destructor, which runs and deletes the dynamic memory when the object goes out of scope, i.e. when I return it and want to use the data in the memory that has been deleted! I'm doing this for an overloaded addition operator.
I'm trying to do something like:
MyObj operator+( const MyObj& x, const MyObj& y )
{
MyObj z;
// code to add x and y and store in dynamic memory of z
return z;
}
My destructor is simply:
MyObj::~MyObj()
{ delete [] ptr; }
Any suggestions would be much appreciated!
It's OK.
Don't worry, before deletion, your object will be copied into another object or will be used temporary.
But...
Try to write a well defined copy-constructor (if you don't have it).
You should obey rule of five.
On the other hand, your code has a good chances for RVO optimization to avoid unnecessary copies and one extra destructing.
Moreover, C++11 presents move semantics to avoid unnecessary copies. To have this, you should write move-constructor and move-assignment.
You need to provide a copy constructor that copies the contents of ptr to the new object.
If MyObj does not have a copy constructor that copies the contents of ptr then you returned object will have its ptr point to deleted memory. Needless to say, if you try to access ptr in this situation, then bad things will happen.
Generally, if you had to write a destructor for your class, you should also write a copy constructor and the assignment operator to handle the copying of any dynamic memory or other resources. This is the Rule of Three mentioned by WhosCraig.
If you are using a modern compiler that supports C++11, you may also want to read up on the move semantics
I have the following code in one of my methods:
vector<Base*> units;
Base *a = new A();
Base *b = new B();
units.push_back(a);
units.push_back(b);
Should I destroy the a and b pointers before I exit the method?
Or should I somehow just destroy the units vector of pointers?
Edit 1:
This is another interesting case:
vector<Base*> units;
A a;
B b;
units.push_back(&a);
units.push_back(&b);
What about this case? Now I don't have to use delete nor smart pointers.
Thanks
If you exit the method, units will be destroyed automatically. But not a and b. Those you need to destroy explicitly.
Alternatively, you could use std::shared_ptr to do it for you, if you have C++11.
std::vector<std::shared_ptr<Base>> units;
And you just use the vector almost as you did before, but without worrying about memory leaks when the function exists. I say almost, because you'll need to use std::make_shared to assign into the vector.
A rather old-fashioned solution, that works with all compilers:
for ( vector<Base*>::iterator i = units.begin(); i != units.end(); ++i )
delete *i;
In C++11 this becomes as simple as:
for ( auto p : units )
delete p;
Your second example doesn't require pointer deallocation; actually it would be a bad error to do it. However it does require care in ensuring that a and b remain valid at least as long as units does. For this reason I would advise against that approach.
You need to iterate over the vector and delete each pointer it contains. Deleting the vector will result in memory leaks, as the objects pointed to by its elements are not deleted.
TL;DR: The objects remain, the pointers are lost == memory leak.
Yes you should destroy those pointers (assuming you aren't returning the vector elsewhere).
You could easily do it with a std::for_each as follows:
std::for_each( units.begin(), units.end(), []( Base* p ) { delete p; } );
You should not delete if this two situation match.
Created vector return to out side of the function.
Vector created outside of the function and and suppose to access from other functions.
In other situations you should delete memory pointed by pointers in vector. otherwise after you delete the pointers, no way to refer this memory locations and it calls memory leak.
vector<Base*>::iterator it;
for ( it = units.begin(); it != units.end(); ){
delete * it;
}
I would suggest that you use SmartPointers in the vector. Using smart pointers is a better practice than using raw pointers. You should use the std::unique_ptr, std::shared_ptr or std::weak_ptr smart pointers or the boost equivalents if you don't have C++11. Here is the boost library documentation for these smart pointers.
In the context of this question, yes you have to delete the pointers that are added to the vector. Else it would cause a memory leak.
You have to delete them unless you will have memory leak , in the following code if I comment the two delete lines the destructors never called, also you have to declare the destuctor of the Base class as virtual. As others mentioned is better to use smart pointers.
#include <iostream>
#include <vector>
class Base
{
public:
virtual ~Base(){std::cout << "Base destructor" << std::endl;};
};
class Derived : public Base
{
~Derived(){std::cout << "Derived destructor" << std::endl;};
};
int main()
{
std::vector<Base*> v;
Base *p=new Base();
Base *p2=new Derived();
v.push_back(p);
v.push_back(p2);
delete v.at(0);
delete v.at(1);
};
Output:
Base destructor
Derived destructor
Base destructor
Output with non-virtual base destructor (memory leak):
Base destructor
Base destructor
Yes and no. You don't need to delete them inside the function, but for other reasons than you might think.
You are essentially giving ownership of the objects to the vector, but the vector is not aware of that and therfore wont call delete on the pointers automatically. So if you store owning raw pointers in a vector, you have to manually call delete on them some time. But:
If you give the vector out of your function, you should not destroy the objects inside the function, or the vector full of pointers to freed memory would be pretty useless, so no. But in that case, you should make sure the objects are destroyed after the vector has been used outside the function.
If you don't give the vector out of the function, you should destroy the objects inside the function, but there would be no need to allocate them on the free store, so don't use pointers and new. You just push/emplace the objects themselves into the vector, it takes care of the destruction then, and therfore you don't need delete.
And besides that: Don't use plain new. Use smart pointers. Regardless what you do with them, the smart pointers will take care of a proper destruction of the objects contained. No need to use new, no need to use delete. Ever. (Except when you are writing your own low level data structures, e.g. smart pointers). So if you want to have a vector full of owning pointers, these should be smart pointers. That way you won't have to worry about wether, when and how to destroy the objects and free the memory.
The best way to store pointers in a vector will be to use smart_ptr instead of raw pointers. As soon as the vector DTOR is called and control exits the DTOR all smart_ptrs will be refernced counted. And you should never bothered about the memory leak with smart_ptrs.
In the first example, you will eventually have to delete a and b, but not necessarily when units goes out of scope. Usually you will do that just before units goes out of scope, but that is not the only possible case. It depends on what is intended.
You might (later in the same function) alias a or b, or both, because you want them to outlive units or the function scope. You might put them into two unit objects at the same time. Or, many other possible things.
What's important is that destroying the vector (automatic at scope end in this case) destroys the elements held by the vector, nothing more. The elements are pointers, and destroying a pointer does nothing. If you also want to destroy what the pointer points to (as to not leak memory), you must do that manually (for_each with a lambda would do).
If you don't want to do this work explicitly, a smart pointer can automatize that for you.
The second example (under Edit1) does not require you to delete anything (in fact that's not even possible, you would likely see a crash attempting to do that) but the approach is possibly harmful.
That code will work perfectly well as long as you never reference anything in units any more after a and b left scope. Woe if you do.
Technically, such a thing might even happen invisibly, since units is destroyed after a, but luckily, ~vector does not dereference pointer elements. It merely destroys them, which for a pointer doesn't do anything (trivial destructor).
But imagine someone was so "smart" as to extend the vector class, or maybe you apply this pattern some day in the future (because it "works fine") to another object which does just that. Bang, you're dead. And you don't even know where it came from.
What I really don't like about the code, even though it is strictly "legal" is the fact that it may lead to a condition which will crash or exhibit broken, unreproducable behaviour. However, it does not crash immediately. Code that is "broken" should crash immediately, so you see that something is wrong, and you are forced to fix it. Unluckily that's not the case here.
This will appear to work, possibly for years, until one day it doesn't. Eventually you'll have forgotten that a and b live on the current stack frame and reference the non-existing objects in the vector from some other location. Maybe you dynamically allocate the vector in a future revision of your code, since you pass it to another function. And maybe it will continue to appear working.
And then, you'll spend hours of your time (and likely the time of others) trying to find why a section of code that cannot possibly fail produces wrong results or crashes.
Warning against your second example.
This simple extension leads to undefined behavior:
class A {
public:
int m;
A(int _m): m(_m) {}
};
int main(){
std::vector<A*> units;
for (int i = 0; i < 3; ++i) {
A a(i);
units.push_back(&a);
}
for (auto i : units) std::cout << i->m << " "; // output: 2 2 2 !!!!
return 0;
}
In each loop, the pointer to each a is saved in units, but the objects that they point to go out of scope. In the case of my compiler, the memory address of each a was re-used each time, resulting in units holding three identical memory addresses -- all pointing to the final a object.
I'm trying to follow a tutorial here: regarding overloading operators, and I've found something that's really confused me.
There was a previous question on this very website here where this tutorial was discussed, namely regarding how the variables in the class were preserved because the whole class was passed back by value.
Whilst experimenting with the class definition I toyed with making the integer variables pointers (perhaps not sensible - but just to experiment!) as follows:
class CVector {
int* x;
int* y;
public:
CVector () {};
CVector (int,int);
CVector operator + (CVector);
~CVector ();
};
In the class constructor I allocate memory for the two integers, and in the class deconstructor I delete the allocated memory.
I also tweak the overloaded operator function as follows:
CVector CVector::operator+ (CVector param) {
CVector temp;
*temp.x = *x + *param.x;
*temp.y = *y + *param.y;
return (temp);
}
For the original code, where the class has simple integer variables the return by value of the entire class completes successfully.
However, after I change the variables to int pointers, the return by value of the class does not complete successfully as the integer variables are no longer intact.
I assume the deconstructor is being called when the temporary CVector goes out of scope and deletes these member integer pointers, but the class itself is still returned by value.
I'd like to be able to return by value the CVector with the memory allocated to its member variables intact, whilst ensuring the temporary CVector is correctly deleted when it goes out of scope.
Is there any way this can be done?
Many thanks!
The problem is that you are not following the rule of the three, which basically boils down to: *if you manage resources, then you should provide copy constructor, assignment operator and destructor for your class*.
Assuming that on construction you are allocating memory for the pointers, the problem is that the implicit copy constructor is shallow, and will copy the pointers, but you probably want a deep copy. In the few cases where you do not want a deep copy, control of the manage shared resource becomes more complicated, and I would use a shared_ptr rather than trying to do it manually.
You need to provide a copy constructor for CVector to make copies of the allocated memory. Otherwise, when you return by value, the pointer values will simply be copied and then the temp object is destructed, deallocating the ints. The returned copy now points to invalid memory.
CVector( const CVector& other )
: x ( new int(other.x) )
, y ( new int(other.y) )
{}
Note that it is bad idea to be using raw pointers in your class, especially more than one. If the allocation of y fails above and new throws you've got a memory leak (because x is left dangling). You could've allocated within the constructor itself, instead of the initializer list, either within a try-catch, or using the std::nothrow version of new, then check for nullptr. But it makes the code very verbose and error prone.
The best solution is to use some smart pointer class such as std::unique_ptr to hold pointers. If you were to use std::shared_ptr to hold those pointers, you can even share the ints between copies of the class.
The return-by-value causes the returned, temp object to be copied to another object, a temporary "return object". After temp is copied, it is destructed, deallocating your ints. The easiest way to handle this is to use a reference-counted pointer such as tr1::shared_ptr<>. It will keep the memory allocated until the last reference to it is dropped, then it will deallocate.
There are few problems in the given code.
(1) You should allocate proper memory to *x and *y inside the constructor; otherwise accessing them is undefined behavior.
CVector () : x(new int), y(new int) {}
Also make sure that to have copy constructor and operator = where you delete x and delete y before reallocating them; otherwise it will lead to hazards.
(2) delete them in destructor
~CVector () { delete x; delete y; }
(3) Pass argument to operator + by const reference to avoid unnecessary copying.
CVector CVector::operator+ (const CVector ¶m)
{
// code
}
Since you are learning with playing around with pointers, I will not comment on the design perspective of your class, like if they should be pointer or variables or containers and so on.