I am reading failing constructors from C++ FAQ and don't understand the following code.
void f()
{
X x; ← if X::X() throws, the memory for x itself will not leak
Y* p = new Y(); ← if Y::Y() throws, the memory for *p itself will not leak
}
How is it possible that the memory pointed to by p will not leak if the constructor throws? I assumed the sequence is as follows.
Memory is allocated for object Y.
Y's constructor is called.
Y's constructor throws and memory pointed to by p leaks.
If Y's constructor throws, then the stack is unwound, including deleting the memory allocated for Y.
The problems arise primarily when/if you have more than one object to deal with. For example:
void f() {
X *x = new X();
Y *y = new Y();
}
Now, if the new X() part succeeds, but the new Y() part fails, the memory allocated for y will be deleted, but x will not be destroyed, and its memory will be leaked. You can work around this problem with try blocks, if you really insist:
try {
X *x = new X();
Y * y = new Y();
}
catch (y_construction_failed) {
delete x;
}
The big problem with this is that you have to nest the try blocks if you have more than two items, so if you need, say, half a dozen local variables, it's going to be deeply nested and excruciatingly ugly.
You will run into a similar problem having a function void f(X*, Y*) and calling f(new X(), new Y()). If one of the new calls succeeds and the other fails you have a memory leak. To resolve it you might create additional functions 'X* make_X()' and 'Y* make_Y()' returning pointers. Now, f(make_X(), make_Y()) is safe. (And after going that far, you might use smart pointers)
It's important to notice that even though the object is deleted, its destructor is not called in this case.
This makes sense, since an exception during construction indicates that the object was never fully constructed (ie. its class invariants have not been established), so calling the destructor could be dangerous.
The downside of this is that if the constructor performs actions that require cleanup which would normally be performed by the destructor, it is now the constructor's responsibility to perform this cleanup in case of exceptions. Take the following example:
class C {
private:
int* p1;
int* p2;
public:
C() : p1(new int()), p2(new int()) {}
~C() { delete p1; delete p2; }
};
If the allocation p2 throws, the memory already allocated for p1 will leak. It is your responsibility as a programmer to write constructors in a way that this cannot happen.
The easiest way to achieve this is by delegating the resource management responsibilities to a RAII container class like unique_ptr. That way, no class is responsible for managing more than one resource and scenarios like the one outlined above can no longer occur.
Related
#include <iostream>
struct ABC{
int A;
ABC(int i = 1) : A(i) {}
~ABC() {
std::cout << A << std::endl;
}
void destruct() {
delete this;
}
};
int main() {
ABC A1(2);
A1.destruct();
return 0;
}
Output:
2
2
I have this code in which I'm trying to manually delete structure variable. Doing so, I realized the destructor gets called twice here. Why is this happening? Why isn't it getting deleted when destruct() is called?
The delete this call causes undefined behaviour, which means that anything at all can happen.
delete may only be used for objects created by new.
For automatic objects with a non-trivial destructor (e.g. your A1), it is not possible to "destroy them early" unless you also create another ABC in the same place before the scope ends. In other words you can't "turn off" the destruction process that occurs when the scope ends.
Why isn't [my object] getting deleted when destruct() is called?
When an object gets destructed in C++, it does not mean that the object disappears. It means that the clean-up code from the destructor gets executed, and that any access to the object's members from that point on is invalid.
When you call destruct() you try to free object's memory by calling delete. This is undefined behavior in itself, because you have not allocated the object with new. This call causes the first printout.
However, since your object is in automatic memory, C++ is required to call its destructor when the object gets out of scope. This is the call that causes the second printout.
Note: You can fix your code by allocating A1 in dynamic memory:
int main() {
ABC *A1 = new ABC(2);
A1->destruct();
return 0;
}
Now you get a single printout (demo). However, the practice of hiding delete in a member function is questionable.
This is RAII working plus you committing suicide on an object. Calling the destructor on an object is almost always wrong! And calling the destructor twice is always wrong, as it invokes undefined behaviour.
You have to understand that C++ is handling memory for you, if you just let it:
struct Foo{};
int main() {
Foo f; // automatic storage, gets destroyed
// when object gets out of scope
Foo* g = new Foo(); // heap allocated
delete g; // only here you have to delete
}
Just remember: Do not delete anything that you did not create via new (thanks to Mike Vine for the comment). And do not use (naked) heap allocation unless you need to.
Two points to consider here :-
1) Destructor for stack objects will always be called when they go out of scope. So no need to worry for their deallocation.
2) You cannot & should not use delete on the object allocated on stack. In general, you should not use delete this as long as you are not sure that this will be executed only as a consequence of deleting heap objects and after that you are not referring to that object.
So I was looking at this question Memory Allocation Exception in Constructor where my boss states in his beautiful answer that the destructor will not be called.
Which makes me wonder,
If I were to write
struct XBase
{
int* a;
char* b;
float* c;
XBase() : a(nullptr), b(nullptr), c(nullptr) {}
~XBase()
{
delete[] a; delete[] b; delete[] c;
}
};
and
struct X : XBase
{
X() {
a = new int[100];
b = new char[100];
c = new float[100];
}
}
Then, if the allocation of c fails (with an exception being thrown), then the destructor of XBase would be called, since the base class has been constructed.
And no memory leak?
Am I correct?
You are right; this will work, because:
By the time X constructor body is executed, XBase is already constructed, and its destructor will be called.
Doing delete or delete[] on null pointers is perfectly valid, and does nothing.
So, if the allocation of a, b or c fails, the destructor of XBase will deallocate everything.
But, obviously, this design makes you write much more code that needed, since you can simply use std::vector or std::unique_ptr<T[]>.
Just to have a formal version here to back up the claims,
§ 15.2/2
An object of any storage duration whose initialization or destruction is terminated by an exception will have destructors executed for all of its fully constructed subobjects [...].
If you're concerned about the memory allocation failing, I would put it in a separate method, like a Build or Create. You could then let the destructor handle it if it has been initialized (but definitely check pointer before blindly delete-ing.
Another solution is smart pointers, which are not designed to fit this case necessarily, but do automatically deallocate their contents.
I will first post my test program in C++ :
#include <iostream>
using namespace std;
class X
{
int x;
public:
X()
{
cout<<"constructing\n";
x=0;
}
int& getx()
{
return x;
}
~X()
{
cout<<"destroying\n";
}
};
int main()
{
X* p=(X*)malloc(sizeof(X));
++p->getx();
p->getx()*=5;
cout<<p->getx();
free(p);
return 0;
}
Output :
5
Now before anyone complains why i used malloc & free in a C++ program, I would like to reiterate that it is just a test program and the above could have been done even with operator new & operator delete. But my questions still remain the same that are:
Even though no object of X is created using malloc or operator new how can we access the class X's variable x ?
Clearly free & operator delete also do not destroy the objects and perform mere dallocations. What would happen if I create an object with new but use operator delete or free instead of delete ? Would my object still be there & will it be still usable ?
If you deallocate an object created with new by calling free(), you are deep into undefined behavior. Likewise, if you deallocate a malloc()'ed object with delete, you have undefined behavior. Whatever you do, never mix the two.
malloc() has different semantics than new: malloc() just allocates the memory, it does not call a constructor. new does the allocation, and also calls the appropriate constructor.
Likewise, there is the analogue difference between free() and delete: delete calls the destructor before freeing the memory, free() does not.
You can use malloc() in C++ to back a true C++ object, but you will have to do the constructor/destructor calls yourself:
//The placement-new below needs this:
#include <new>
//This is what new does:
char* temp = (char*)malloc(sizeof(Foo)); //allocation only
Foo* foo = new(temp) Foo(); //placement-new: construction only
//This is what delete does:
foo->~Foo(); //destruction only
free((void*)foo); //deallocation only
Note that the placement-new syntax in the second line is the only way to explicitly call a constructor in C++. The destructor can be called explicitly just like any other member. The reason for this asymmetry is that the object really is a valid object before destruction, which is not the case before construction.
To your question about why p->getx() compiles. That comes down to this little cast in your code:
X* p=(X*)malloc(sizeof(X));
^
|
this little cast
Here you, the programmer, are explicitly telling the compiler: "I know that the value I'm giving you does not look like a pointer to X, but I tell you that it is. So, stupid compiler, just shut up about the type mismatch, and treat it as a pointer to X anyway, because I, the human, your god, told you so!"
So what can your compiler do? It shuts up about the type mismatch, and treats the pointer as a pointer to X, as you told it. If that's wrong, that's your problem. Maybe the program will run fine anyway, maybe it crashes, maybe it silently corrupts data, maybe a pink elephant appears. Your compiler won't care. It's only care is that it did your wish. Compilers can be very obedient.
Answering this part of the question: "What would happen if I create an object with new but use operator delete or free instead of delete ? Would my object still be there & will it be still usable ?"
Allocating with malloc and freeing with delete is undefined behavior. There is no guarantee that the implementation will use C's free after calling the object's destructor.
Likewise the opposite. If you allocate with new, there is no guarantee that the returned pointer came from an internally called malloc, realloc or calloc, only cases that it would be safe to pass the pointer to free.
Even if it works, it may break the program and/or leak resources, because you would either skip object's constructor or destructor.
EDIT:
You said "Clearly free & operator delete also do not destroy the objects and perform mere dallocations." Well, that is wrong. delete will call object's destructor, so it will destroy and then deallocate.
As for the clarified question in comments, for "why can you still access x", well, malloc will allocate the full space occupied by the object (which, in your case, I believe to be just the x variable), and the variable will be there, only the constructor will not be called, so, its value will not be set to zero. If it was initially zero when you ran the program, it was merely a coincidence.
Reading so many points from so many I myself wrote a program to explain your problem. See below :-
#include <iostream>
#include <vector>
using namespace std;
class X
{
int x;
vector<int> v;
public:
X()
{
cout<<"constructing\n";
x=0;
v.push_back(1);
v.push_back(2);
}
int& getx()
{
return x;
}
vector<int>& getv()
{
return v;
}
~X()
{
cout<<"destroying\n";
}
};
int main()
{
X* p=(X*)operator new(sizeof(X));
++p->getx();
p->getx()*=5;
cout<<p->getx()<<"\n";
for (int x:p->getv())
cout<<x<<" ";
cout<<"\nexecuted\n";
operator delete(p);
return 0;
}
/* Output :-
5
executed
*/
See how p ignored the vector v and went for the line executed. This is because vector<int> being a class (or more precisely a class template) was never created by operator new (or malloc in your case). Your program showed the output for x because it is a primitive type & not a class. For a class you need a constructor & hence operator new or malloc aren't suitable for classes & hence the output. If you simply replace operator new with new & operator delete with delete then the output will be :-
constructing
5
1 2
executed
destroying
Now your code gives the correct & apt results ! Congo !
For your second question, NEVER MIX UP malloc & free with new & delete as it creates UB with not so happening results.
I've been looking at some code I'm working on, and we have the equivalent of this:
AutoPtr<A> x;
...
/// x gets initialized
...
B* y = new B(x.Detach());
Where AutoPtr is our version of auto_ptr, and Detach() returns the owned pointer and resets itself. Also, B() takes ownership of x.
Now, I realized that this will leak x if new throws an std::bad_alloc, so I changed the code to this:
AutoPtr<A> x;
...
/// x gets initialized
...
B* y = new B(x.Get());
x.Detach();
But then I realized that if B() 'owns' the pointer, and an exception happens during its construction, it should take care of deleting the parameter itself (or should it?), so the x will get deleted twice, once by B(), and once by x's destructor.
Now, is there a C++ idiom that gets around this problem, for example, making code that calls constructors responsible for cleaning up parameters? Most code I've seen doesn't seem to do that...
The obvious solution seems to be to pass a temporary AutoPtr<A> to the constructor of B:
AutoPtr<B> y(new B(AutoPtr<A>(x));
(this also adds resource control for the B* returned from new B()).
B's constructor would just call x.Detach() to initialize whatever it needs to initialize with the A*. If an exception occurs at any point, the AutoPtr<A> will release the object.
If you want to retain the A object managed by x in case of an exception, you can pass a AutoPtr<A>& to the constructor of B instead.
...it should take care of deleting the parameter itself (or should it?)
No, it should not.
B doesn't exist until the constructor completes, and if it doesn't exist it shouldn't claim ownership of anything (to a point; if the constructor itself did something, that needs to be safe as well).
The C++ idiom is to not use raw pointers for ownership (including for y)! B should accept the AutoPtr as an argument so the caller can give up ownership this way. This is the goal of std::unique_ptr and std::move:
std::unique_ptr<A> x;
std::unique_ptr<B> y(new B(std::move(x)));
Also note that really new should not be used like this as well; instead use the make_* utilities:
auto y = std::make_unique<B>(std::move(x));
But this is missing currently as oversight.
Something like this, may be:
B* y = new B();
y->Attach(x.Detach());
or
B* y = new B();
(*y) = x;
I was reading this question Does calling a destructor explicitly destroy an object completely? where this situation comes up in code.
Object* aWidget = new Widget(); //allocate and construct
aWidget->~Object(); //destroy and DON'T deallocate
From the answers, I undrestand that the memory region is in fact not deallocated in this situation. My question is (more out of curiosity than anything):
How can I delete the memory pointed to by aWidget after the two lines of code above have executed? I would assume calling delete aWidget; would fail because it would try to run the destructor on an already-destructed object. Could you call free(aWidget) or something like that instead to just target the memory?
free would, factually speaking, be my best guess. However I don't think you can do anything without invoking UB. How did you arrive at a requirement to invoke the destructor like that?
Calling free on an object allocated with new is undefined behavior.
I suggest you keep it simple, and call delete.
However, if you want to do this, you can, in some cases, call delete even if you previously called the destructor explicitly. If you call it explicitly, you can view it as a function. The memory isn't freed, so I'm guessing setting member pointers to NULL after you destroy them would be enough to prevent you from running into any trouble. (because calling delete on a NULL pointer is a no-op).
For example, the following should be ok:
class A
{
public:
int * x;
A()
{
x = new int[10];
}
~A()
{
delete[] x;
x = NULL;
}
};
int main()
{
A* a = new A;
a->~A();
delete a;
return 0;
}