I am new to C++ style casts, and need help in understanding how the code below works (this is some dummy code I wrote to understand things).
#include <iostream>
#include <memory>
class A {
public:
A() : a(1) {
std::cout << "Creating A\n";
}
~A() {
std::cout << "Destroying A\n";
}
int a;
};
class B : public A {
public:
B() : b(2) {
std::cout << "Creating B\n";
}
~B() {
std::cout << "Destroying B\n";
}
int b;
};
int main() {
std::shared_ptr<B> objectB(new B());
{
std::shared_ptr<A> (static_cast<A*>(objectB.get()));
std::cout << "End of inner scope\n";
}
std::cout << "End of outer scope\n";
}
It prints
Creating A
Creating B
Destroying A
End of inner scope
End of outer scope
Destroying B
Destroying A
My understanding:
Creating A -> B's ctor calls base class ctor
Creating B -> B's ctor
Destroying A -> ???
End of inner scope
End of outer scope
Destroying B -> B's dtor
Destroying A -> B's dtor calls base dtor
Why do I get the first Destroying A and what exactly is happening here?! How can A be destroyed twice?
If you make sure the output is flushed (by using std::endl, for example), you get
Creating A
Creating B
Destroying A
End of inner scope
End of outer scope
Destroying B
Destroying A
the reason for the double delete of A is that you are constructing a shared_ptr from a raw pointer here:
std::shared_ptr<A> (static_cast<A*>(objectB.get()));
This shared_ptr is completely independent of the first one, and has its own reference count. So when the scope ends, it attempts to delete the A pointer it holds. If you had done this instead:
std::shared_ptr<A>{objectB};
then you wouldn't have encountered the problem. Note there is no need for a static_cast here.
Note that A should have a virtual destructor. shared_ptr has a clever destruction mechanism which means that this is not crucial in this example, but in general, if you are going to delete objects polymorphically, the base class must have a virtual destructor.
Just in case it wasn't clear from juanchopanza's answer, this line
std::shared_ptr<A> (static_cast<A*>(objectB.get()));
is incorrect and leads to undefined behavior.
The shared pointer you construct here just takes the pointer you give it. It has no idea that the object pointed to by that pointer is already owned by another smart pointer. Furthermore it doesn't know that the pointer points to a sub-object and that the pointer will need to be cast back to B* in order to be deleted, because the static_cast hides that information from it.
To cast smart pointers you need a cast that understands and is integrated with smart pointers. C++ has std::static_pointer_cast and std::dynamic_pointer_cast for this purpose.
int main() {
std::shared_ptr<B> objectB(new B());
{
std::shared_ptr<A> x = std::static_pointer_cast<A>(objectB);
std::cout << "End of inner scope\n";
}
std::cout << "End of outer scope\n";
}
With this code the output of your program shows correct behavior:
make A
make B
End of inner scope
End of outer scope
~B
~A
Of course in this particular case you don't need an explicit cast, because std::shared_ptr can figure out legal up-casts and do them implicitly. You need std::static_pointer_cast to do down-casts though:
int main() {
std::shared_ptr<A> objectA(new B());
{
std::shared_ptr<B> x = std::static_pointer_cast<B>(objectA);
std::cout << "End of inner scope\n";
}
std::cout << "End of outer scope\n";
}
Thanks, one last thing, if I don't need objectB, is it safe to do std::shared_ptr<A> objectA(new B());?
Yes, this does happen to be safe. The shared_ptr<A> constructor receives a B* and knows enough to store the fact that when deletion occurs it will need to convert the A* that it holds to B*. This ensures that the object gets deleted correctly.
However, if you really want your types A and B to behave polymorphically then you should probably just make them polymorphic types by adding virtual destructors, and then you don't have to worry about how smart std::shared_ptr is about this.
Related
Have a look at following code:
#include <iostream>
#include <memory>
class A
{
public:
A()
{
std::cout << "A() \n";
}
~A()
{
std::cout << "~A() \n";
}
int a = 100;
};
class B
{
public:
B()
{
ptr.reset(new A());
std::cout << "B() \n";
std::cout << "pointer value" << ptr.get() << std::endl;
std::cout << ptr->a << std::endl;
}
~B()
{
std::cout << "~B() \n";
}
void print()
{
std::cout << "print() " << a << b << "\n";
std::cout << "pointer value" << ptr.get() << std::endl;
std::cout << ptr->a << std::endl;
}
private:
std::unique_ptr<A> ptr;
int a = 10;
int b = 5;
};
int main()
{
std::unique_ptr<B> p1(new B());
p1->~B();
p1->print();
return 0;
}
the output result:
A()
B()
pointer value010ECB60
100
~B()
~A()
print() 105
pointer value010ECB60
-572662307
~B()
~A()
The Question is:
When class B's destructor called, class A's destructor also called, and class A's member a = 100 has been destroyed, but class B's member a = 10; b = 5 still exist, and it's value not changed, so class B's destructor can't be seen as a function, since it called class A's destructor, how to explain this?
When exit the main() function, the destructor of class B called second time automatically, and code breaks with the error code HEAP[Destructor.exe]: Invalid address specified to RtlValidateHeap( 00EA0000, 00EACE38 ), because class B's destructor called first time so object A has been destroyed, this will destroy it twice?
I add some print info to track workflow, but i still don't figure out how it worked when called the destructor explicitly.
When class B's destructor called, class A's destructor also called, and class A's member a = 100 has been destroyed, but class B's member a = 10; b = 5 still exist, and it's value not changed, so class B's destructor can't be seen as a function, since it called class A's destructor, how to explain this?
No, they do not exist, both B and A objects have been destroyed, it is just that dereferencing a dangling pointer (p1.get() during p1->print()) is undefined behaviour. In this case, the compiler just did not bother with clearing the memory locations used for the storage of the object B.
When exit the main() function, the destructor of class B called second time automatically, and code breaks with the error code HEAP[Destructor.exe]: Invalid address specified to RtlValidateHeap( 00EA0000, 00EACE38 ), because class B's destructor called first time so object A has been destroyed, this will destroy it twice?
Well, you destroyed the object held by p1 but in a way p1 was not aware it has been destroyed. Then when ~unique_ptr has been called on p1, it tried to destroy already destroyed object. Instead, you should just use p1.reset() which will call ~B and update p1's state accordingly to prevent the mentioned issue.
To really understand what is going on here, you need to understand there are really two related processes that happen when recycling an object's memory. There's destruction (which is calling the class destructor to clean up any other objects the object refers to), and there's deallocation (which makes the memory available for reuse). Normally for objects on the heap, one calls delete which does both of these things. For std::unique_ptr, its destructor call its deleter, which by default calls delete on the object the unique_ptr points at.
When you call a destructor explicitly (with p1->~B() in your case), it destroys the object but does not deallocate it. That leaves the object in a "broken" state where you can't do anything with it (not even call delete safely), but where it hasn't been deallocated either, so all you can do is kill any references to it (with .release()) and let the memory leak. So you should never call the destructor explicitly.
If you try to access an object after it has been destroyed, you get undefined behavior, but if you try it before the object has been deallocated (as you are doing in your example), you'll probably just see the same data, as the memory has not yet been overwritten by anything else.
Usually you don't need to call destructor explicitly. For automatic objects and dynamically allocated objects (using new/delete) lifetime of object coincides with liftime of its storage, and constructors and destructors called automatically. But sometimes storage is allocated separatelly and in this case constructor(well, sort of) and destructor should be called explicitly. Here is example code from: https://en.cppreference.com/w/cpp/language/new
{
// Statically allocate the storage with automatic storage duration
// which is large enough for any object of type `T`.
alignas(T) unsigned char buf[sizeof(T)];
T* tptr = new(buf) T; // Construct a `T` object, placing it directly into your
// pre-allocated storage at memory address `buf`.
tptr->~T(); // You must **manually** call the object's destructor
// if its side effects is depended by the program.
} // Leaving this block scope automatically deallocates `buf`.
Same techniques used in different containers, for example std::vector.
class A
{
public:
~A()
{
std::cout << "A destroyed" << std::endl;
}
};
class B
{
public:
A a;
~B()
{
std::cout << "B destroyed" << std::endl;
}
};
int main()
{
B b;
b.~B();
}
Output:
B destroyed
A destroyed
B destroyed
A destroyed
Can someone explain to me what's going on here? I expected the output to be
B destroyed
A destroyed
(once when ~B() is called and once ~A() is called).
Any object that was created in a limited scope would be destroyed when the scope is exited.
Meaning, that if you have created an object on the stack, it will be destroyed when the stack will fold back, along with any other variables declared in that scope.
The only exception to this is when you are using dynamic allocation of objects, using the keyword new, this creates the object on the heap, which doesn't clean itself on its own. But even then, calling delete will invoke the destructor on its own.
Having said that, in order to avoid using new and delete, and for better resource management, there are types (such as smart-pointers) that handle these on their own, in a technique called Resource Allocation Is Initialization (or RAII), which makes things much simpler (and you get to the first part, all is allocated on the stack, thus the destructors are being called automatically when it folds).
If class A contains class B, then when A destruct, B's destructor will be called first, i.e., the reversed order of their nested relationship.
But what if A contains a shared_ptr of B, while B contains a raw pointer to A, how should we handle the destructor to make it safe?
Considering the following example:
#include <iostream>
#include <memory>
#include <unistd.h>
struct B;
struct A {
int i = 1;
std::shared_ptr<B> b;
A() : b(std::make_shared<B>(this)) {}
~A() {
b = nullptr;
std::cout << "A destruct done" << std::endl;
}
};
struct B {
A *a;
B(A *aa) : a(aa) {}
~B() {
usleep(2000000);
std::cout << "value in A: " << a->i << std::endl;
std::cout << "B destruct done" << std::endl;
}
};
int main() {
std::cout << "Hello, World!" << std::endl;
{
A a;
}
std::cout << "done\n";
return 0;
}
You can see in A's destructor, I explicitly set b to nullptr, which will trigger B's destructor immediately, and blocking until it finish.
The output will be:
Hello, World!
value in A: 1
B destruct done
A destruct done
done
but if I comment out that line
~A() {
// b = nullptr; // <---
std::cout << "A destruct done" << std::endl;
}
The output will be:
Hello, World!
A destruct done
value in A: 1
B destruct done
done
it seems that A's destructor finished without waiting B to destruct. But in this case, I expected segment fault, since when A already destructed, B tried to access the member of A, which is invalid. But why the program doesn't produce segment fault? Does it happen to be OK (i.e., undefined behavior)?
Also, when I change
{
A a;
}
to
A * a = new A();
delete a;
the output is still the same, no segment fault.
It is important to be precise about what is happening. When A is destroyed, the following events happen in the following order:
A::~A() is called.
The A object's lifetime ends. The object still exists, but is no longer within its lifetime. ([basic.life]/1.3)
The body of A::~A() is executed.
A::~A() implicitly calls the destructors of direct non-static members of A in reverse declaration order ([class.dtor]/9, [class.base.init]/13.3)
A::~A() returns.
The A object ceases to exist ([class.dtor]/16). The memory that it used to occupy becomes "allocated storage" ([basic.life]/6) until it is deallocated.
(All references are to the C++17 standard).
In the second version of the destructor:
~A() {
std::cout << "A destruct done" << std::endl;
}
after the statement is printed, the member b is destroyed, which causes the owned B object to be destroyed. At that point, i has not yet been destroyed, so it is safe to access it. After that, the B destructor returns. Then, i is "destroyed" (see CWG 2256 for some subtleties). Finally, the destructor of A returns. At that point, it would no longer be legal to attempt to access the member i.
B has a pointer to A, but doesn't deallocate the memory of it (e.g. no delete). So The pointer is removed but not the memory allocated, which is all fine.
Basically, the pointer is on the stack and it contains the address of some (assumed) allocated memory on the heap. Yes it get removed from the stack, but the allocated memory remains. That's what delete is for. To remove the allocated memory on the heap. However in your case, you don't want that memory to be removed and your pointer is what we call a non-owning pointer. It points to something, but it's not responsible about the cleanup (actually B doesn't own the memory that the pointer is pointing to).
Just wanted to point out that your comment is incorrect:
~A() {
std::cout << "A destruct done" << std::endl;
}
A destructor is DONE when you get out of the curly braces. You can see that in a debugger, doing step-by-step. That is where b will be deleted.
If class A contains class B, then when A destruct, B's destructor will be called first, i.e., the reversed order of their nested relationship.
No. If you destroy an object of type A, that calls the destructor of A, so that is called first.
However, call to B's destructor will finish first: The destructor of A begins by executing the destructor body, and then proceeds to destroy the sub objects. The destructor body finishes first, then the sub object destructors, and finally the destructor of A will be complete.
But what if A contains a shared_ptr of B, while B contains a raw pointer to A, how should we handle the destructor to make it safe?
In the destructor body of A, make the pointed B point somewhere else other than the object that is being destroyed:
~A() {
b->a = nullptr;
}
If you point it to null such as in my shown example, then you must also make sure that B can handle the situation that B::a may be null i.e. check before accessing through the pointer.
it seems that A's destructor finished without waiting B to destruct.
That's not what we observe. The body of the destructor of A has finished, but the destructor does not finish until the member destructors finish first.
Say there is an object A which owns an object B via std::unique_ptr<B>. Further B holds a raw pointer(weak) reference to A. Then the destructor of A will invoke the destructor of B, since it owns it.
What will be a safe way to access A in the destructor of B? (since we may also be in the destructor of A).
A safe way me be to explicitly reset the strong reference to B in the destructor of A, so that B is destroyed in a predictable manner, but what's the general best practice?
I'm no language lawyer but I think it is OK. You are treading on dangerous ground and perhaps should rethink your design but if you are careful I think you can just rely on the fact that members are destructed in the reverse order they were declared.
So this is OK
#include <iostream>
struct Noisy {
int i;
~Noisy() { std::cout << "Noisy " << i << " dies!" << "\n"; }
};
struct A;
struct B {
A* parent;
~B();
B(A& a) : parent(&a) {}
};
struct A {
Noisy n1 = {1};
B b;
Noisy n2 = {2};
A() : b(*this) {}
};
B::~B() { std::cout << "B dies. parent->n1.i=" << parent->n1.i << "\n"; }
int main() {
A a;
}
Live demo.
since the members of A are destructed in order n2 then b then n1. But this is not OK
#include <iostream>
struct Noisy {
int i;
~Noisy() { std::cout << "Noisy " << i << " dies!" << "\n"; }
};
struct A;
struct B {
A* parent;
~B();
B(A& a) : parent(&a) {}
};
struct A {
Noisy n1 = {1};
B b;
Noisy n2 = {2};
A() : b(*this) {}
};
B::~B() { std::cout << "B dies. parent->n2.i=" << parent->n2.i << "\n"; }
int main() {
A a;
}
Live demo.
since n2 has already been destroyed by the time B tries to use it.
What will be a safe way to access A in the destructor of B? (since we may also be in the destructor of A).
There isn't safe way:
3.8/1
[...]The lifetime of an object of type T ends when:
— if T is a class type with a non-trivial destructor (12.4), the destructor call starts [...]
I think it's straightforward that you can't access object after it's lifetime has ended.
EDIT: As Chris Drew wrote in comment you can use object after it's destructor started, sorry, my mistake I missed out one important sentence in the standard:
3.8/5
Before the lifetime of an object has started but after the storage which the object will occupy has been
allocated or, after the lifetime of an object has ended and before the storage which the object occupied is
reused or released, any pointer that refers to the storage location where the object will be or was located
may be used but only in limited ways. For an object under construction or destruction, see 12.7. Otherwise,
such a pointer refers to allocated storage (3.7.4.2), and using the pointer as if the pointer were of type void*,
is well-defined. Such a pointer may be dereferenced but the resulting lvalue may only be used in limited
ways, as described below. The program has undefined behavior if:
[...]
In 12.7 there is list of things you can do during construction and destruction, some of the most important:
12.7/3:
To explicitly or implicitly convert a pointer (a glvalue) referring to an object of class X to a pointer (reference)
to a direct or indirect base class B of X, the construction of X and the construction of all of its direct or
indirect bases that directly or indirectly derive from B shall have started and the destruction of these classes shall not have completed, otherwise the conversion results in undefined behavior. To form a pointer to (or
access the value of) a direct non-static member of an object obj, the construction of obj shall have started
and its destruction shall not have completed, otherwise the computation of the pointer value (or accessing
the member value) results in undefined behavior.
12.7/4
Member functions, including virtual functions (10.3), can be called during construction or destruction (12.6.2).
When a virtual function is called directly or indirectly from a constructor or from a destructor, including
during the construction or destruction of the class’s non-static data members, and the object to which the
call applies is the object (call it x) under construction or destruction, the function called is the final overrider
in the constructor’s or destructor’s class and not one overriding it in a more-derived class. If the virtual
function call uses an explicit class member access (5.2.5) and the object expression refers to the complete
object of x or one of that object’s base class subobjects but not x or one of its base class subobjects, the
behavior is undefined.
As has already been mentioned there is no "safe way". In fact as has been pointed out by PcAF the lifetime of A has already ended by the time you reach B's destructor.
I also just want to point out that this is actually a good thing! There has to be a strict order in which objects get destroyed.
Now what you should do is tell B beforehand that A is about to get destructed.
It is as simple as
void ~A( void ) {
b->detach_from_me_i_am_about_to_get_destructed( this );
}
Passing the this pointer might be necessary or not depending on the design ob B (If B holds many references, it might need to know which one to detach. If it only holds one, the this pointer is superfluous).
Just make sure that appropriate member functions are private, so that the interface only can be used in the intended way.
Remark:
This is a simple light-weight solution that is fine if you yourself completely control the communication between A and B. Do not under any circumstances design this to be a network protocol! That will require a lot more safety fences.
Consider this:
struct b
{
b()
{
cout << "b()" << endl;
}
~b()
{
cout << "~b()" << endl;
}
};
struct a
{
b ob;
a()
{
cout << "a()" << endl;
}
~a()
{
cout << "~a()" << endl;
}
};
int main()
{
a oa;
}
//Output:
b()
a()
~a()
~b()
"Then the destructor of A will invoke the destructor of B, since it owns it." This is not the correct way of invocation of destructors in case of composite objects. If you see above example then, first a gets destroyed and then b gets destroyed. a's destructor won't invoke b's destructor so that the control would return back to a's destructor.
"What will be a safe way to access A in the destructor of B?". As per above example a is already destroyed therefore a cannot be accessed in b's destructor.
"since we may also be in the destructor of A).". This is not correct. Again, when the control goes out of a's destructor then only control enters b's destructor.
Destructor is a member-function of a class T. Once the control goes out of destructor, the class T cannot be accessed. All the data-members of class T can be accessed in class T's constructors and destructor as per above example.
If you look only on the relations of the two classes A and B, the construction is well:
class A {
B son;
A(): B(this) {}
};
class B {
A* parent;
B(A* myparent): parent(myparent) {}
~B() {
// do not use parent->... because parent's lifetime may be over
parent = NULL; // always safe
}
}
The problems arise, if objects of A and B are proliferated to other program units. Then you should use the tools from std::memory like std::shared_ptr or std:weak_ptr.
I try to understand what happen when an object destroy on stack.
here is my sample code:
#include <stdio.h>
struct B {
~B() {puts("BBBB");}
};
int main()
{
B b;
b.~B();
}
output is
BBBB
BBBB
based on the output, I can tell the object is destroy twice.one is ~B(), another one is after "}". how and why can a object get destroy twice?
update:
after i review replies, I think the destructor doesnt destroy this object. it there a way to destroy an object before it reach out of scope "}".
Thanks
You are not supposed to invoke the destructor by hand. What's happening is you are invoking the destructor and then when the object gets popped off the stack the destructor is called again automatically by the compiler.
~B() is called before the destruction
Destructors are usually used to deallocate memory and do other cleanup
for a class object and its class members when the object is destroyed.
A destructor is called for a class object when that object passes out
of scope or is explicitly deleted.
Source
So you are just calling a function twice.
There's minimal-to-no garbage collection in C++, objects are simply destroyed when they go out of scope. So you could replace your test to this:
#include <iostream>
struct B {
B() { std::cout << "B()" << std::endl; }
~B() { std::cout << "~B()" << std::endl; }
};
int main()
{
std::cout << "start main" << std::endl;
{ // scope
std::cout << "start scope" << std::endl;
B b;
std::cout << "end scope" << std::endl;
} // <-- b gets destroyed here.
std::cout << "end main" << std::endl;
}
If you want an object on the stack over which you have control over the lifetime of, you can do something like this:
#include <iostream>
#include <memory.h>
struct B {
B() { std::cout << "B()" << std::endl; }
~B() { std::cout << "~B()" << std::endl; }
};
int main()
{
std::cout << "start main" << std::endl;
{ // scope
std::cout << "start scope" << std::endl;
void* stackStorage = alloca(sizeof(B));
std::cout << "alloca'd" << std::endl;
// use "in-place new" to construct an instance of B
// at the address pointed to by stackStorage.
B* b = new (stackStorage) B();
std::cout << "ctord" << std::endl;
b->~B(); // <-- we're responsible for dtoring this object.
std::cout << "end scope" << std::endl;
} // <-- b gets destroyed here, but it's just a pointer.
std::cout << "end main" << std::endl;
}
Live demo: http://ideone.com/ziNjkd
Remember, though, it's the stack. When it goes out of scope, it goes away - if you don't destroy it, it just dissapears.
{
void* stackStorage = alloca(sizeof(B));
B* b = new (stackStorage) B(); // "in-place new"
} // (*b)s memory is released but (*b) was not dtord.
The only time you would manually call a destructor is when you've got grounds to use placement new
Keep in mind that the destructor is like any other function. The only difference with other function is that it is automatically called when the object is deallocated. You cann see this like an event. You get a chance to clean everything before the object get annihilated. Calling the destructor by hand does not deallocate the object.
Object construction/destruction in C++ follows this simple rule:
Anything automatically allocated (and constructed) is automatically destructed.
Anything explicitely allocated with new is explicitely destructed via delete.
Anything explicitely constructed with new() must be explicitely destructed by calling the destructor.
The destructor has to be called in all three cases, the difference is in how the memory for the object is allocated:
The object is on the stack, its allocation is managed by the compiler.
The object is on the heap, its allocation is managed by the programmer.
The object is anywhere, construction and destruction is independent of allocation.
In the first two cases, we have a combination of allocation and construction, and consequently a combination of destruction and deallocation. The third case is entirely different, but fully supported by the language, and the reason that you are allowed to explicitely call a destructor; because in this case an object is constructed without allocating memory for it. Consequently, it must be destructible without deallocating memory as well. This case can be used like this:
void* buffer = (void*)new char[sizeof(Foo)]; //allocation
Foo* myFoo = new(buffer) Foo(); //construction
myFoo->~Foo(); //destruction
Foo* anotherFoo = new(buffer) Foo(); //reuse the buffer to construct another object in it
anotherFoo->~Foo(); //destruction of the second object
delete buffer; //deallocation
Note, that this actually constructs two objects, one after the other in the same place, destructing them explicitely before the memory is reused. The buffer could also be a large slap of memory to store many objects, std::vector<> works like this.
So, yes, destruction does destroy your object, you must not use it after destruction. But since you used an automatically allocated and constructed object in your question, the compiler also took care of destructing it, leading to the double destruction. This is always a bug, objects must never be destructed twice, but the language allows you to do it anyway.
What you are doing is a pretty good example of a variable running out of scope.
int main()
{
//Main is started
B b;
/* What happens is that `b` is constructed as a local
variable and put on the runtime stack.*/
b.~B();
/*You then invoke the destructor manually which is bad practice.
But it is possible and it will execute the code.
However, the state of the resulting instance is undefined.*/
}
/*Main ends and local variables defined in the
current scope get destroyed. Which also means that B's destructor
is called the second time */
FYI - the only time you are supposed to do manual destruction of an object is when it is put on the heap like this:
// create an instance of B on the heap
B* b = new B();
// remove instance and implicitly call b's destructor.
delete b;
i would like to answer my own question.
after a lot of reading, Here is my summary.
1. destructor doesnt destroy it's object. the object stays at stack
until out of scope.
2. nothing can destroy a stack object.
3. the destructor did destroy RESOURCE inside the object.
sample code:
struct B {
B() {happy="today is a good day"; hour = 7;}
~B() {puts("BBBB");}
std::string happy;
int hour;
};
int main()
{
B b;
std::cout << b.happy << b.hour <<std::endl;
b.~B();
std::cout << b.happy << b.hour <<std::endl;
}
output:
today is a good day7
BBBB
7
BBBB
we can see a resource b.happy is gone after b.~B() is called. this is a proof of my point 3.
you see the b.hour(int type is not a resource) is still here. this is a proof of my point 1.