unique_ptr does not call the destructor to free the pointer - c++

I am passing unique_ptr to function and then move the pointer to another unique_ptr, all is working fine as need, but while point is unique_ptr does not call destructor of the when it goes out of scope.
Below is my code. and its output, the code is in eclipse.
#include <iostream>
#include <memory>
using namespace std;
class BaseCcExpander;
class DeriveHandler;
class ExpansionRuleExecuter;
class DeriveType1;
class ParamBase
{
public :
ParamBase()
{
std::cout << "Ctor:ParamBase:\n";
}
std::unique_ptr<ExpansionRuleExecuter> paramexpander;
virtual ~ParamBase() { std::cout << "Dtor::~ParamBase:\n"; }
virtual void attachBase(int paramGrp,int paramId,std::unique_ptr<ExpansionRuleExecuter> xbaseExpander);
};
ParamBase* obj;
void ParamBase::attachBase(int paramGrp,int paramId,std::unique_ptr<ExpansionRuleExecuter> xbaseExpander)
{
std::cout << "In: ParamBase::attachHandler :\n";
paramexpander = std::move(xbaseExpander);
}
class ExpansionRuleExecuter
{
public:
ExpansionRuleExecuter()
{
std::cout << "Ctor ExpansionRuleExecuter::ExpansionRuleExecuter:\n" << endl;
}
virtual ~ExpansionRuleExecuter(){
std::cout << "Dtor ~ExpansionRuleExecuter::ExpansionRuleExecuter:\n" << endl;
}
virtual void handleExpansion() = 0;
};
class DeriveHandler : public ExpansionRuleExecuter
{
public:
DeriveHandler()
{
std::cout << "Ctor::DeriveHandler:\n" << endl;
}
~DeriveHandler()
{
std::cout << "Dtor::~DeriveHandler:\n" << endl;
}
void handleExpansion()
{
std::cout << "DeriveHandler expanded\n" << endl;
}
};
ParamBase *obj1;
class BaseCcExpander
{
public:
BaseCcExpander()
{
std::cout << "Ctor::BaseCcExpander:\n" << endl;
}
virtual ~BaseCcExpander()
{
std::cout << "Dtor::~BaseCcExpander:\n" << endl;
}
typedef unique_ptr<ExpansionRuleExecuter> ccHandler;
BaseCcExpander::ccHandler ccBaseHandler;
void attachHandler(int paramGrp, int paramId,std::unique_ptr<ExpansionRuleExecuter> xhandler)
{
std::cout << "BaseCcExpander::attachHandler:\n" << endl;
obj1->attachBase(paramGrp,paramId,std::move(xhandler));
}
};
class DeriveType1 : public ParamBase
{
public :
DeriveType1() { std::cout << "Ctor: DeriveType--------1:\n" << endl;}
~DeriveType1() { std::cout << "Dtor::~DeriveType---------1\n" << endl;}
void attachBase(std::unique_ptr<ExpansionRuleExecuter> xbaseExpander);
};
BaseCcExpander ccexpander;
int main()
{
obj1 = new(DeriveType1);
ccexpander.attachHandler(1,2,std::unique_ptr<ExpansionRuleExecuter>(new DeriveHandler));
if(obj1->paramexpander.get())
{
ExpansionRuleExecuter *expand = obj1->paramexpander.get();
expand->handleExpansion();
}
}

You wrote in a comment:
but by is obj1 not destroying even after the program is over as its in the global space, it should destroy.
There is some misunderstanding here. obj1 is destroyed but the object it points to is not deleted when obj1 is destroyed. If the compiler did that, you won't be able to use:
int main()
{
int i = 10;
int* ip = &i;
// You don't want the run time to call the equivalent of
// delete ip;
// when the function returns. That will lead to undefined behavior
// since ip does not point to memory allocated from the heap.
}
When the program ends, the OS reclaims the memory used by the program but that does not mean that it calls the destructor of obj1.
Had the destructor been responsible for releasing resources other than memory, such as network connections, locks on shared files/folders, etc., they will not be released when the program ends without the destructor getting called.

Your variable pointed by obj1 is not deleted, hence its members would not be destroyed until the delete happens and the unique_ptr will remain alive then the destructor will never be called.
You should either call delete on obj1 at the end of your program or use an unique_ptr on it.

Related

Why are the parent's methods still alive after child's destruction

I don't understand why the '''execute''' function of the Parent class is run. I feel like there are two instances: one for the parent class, one for the child class, but why? Indeed, this program is printing "1 Parent", as i expected "1 Child" or "0 Parent". If i uncomment the delay line, the output will be "1 Child".
I know there is a race condition in this program. This program was only made to understand the working principle of the inheritance in a multithreaded environment.
Thank you !
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <string>
#include <thread>
class Parent
{
public:
std::thread myThread;
int a;
Parent() {
this->myThread = std::thread();
this->a = 0;
}
void start()
{
this->myThread = std::thread(&Parent::execute, this);
}
virtual void execute() {
std::cout << a << " Parent" << std::endl;
}
virtual ~Parent() {
while(!this->myThread.joinable());
this->myThread.join();
}
};
class Child : public Parent
{
public:
Child() {
this->a = 1;
}
void execute() override {
std::cout << a << " Child" << std::endl;
}
~Child() {
}
};
int main()
{
std::cout << "Init" << std::endl;
Child * chld = new Child();
chld->start();
//std::this_thread::sleep_for(std::chrono::milliseconds(x));
std::cout << "Delete" << std::endl;
delete chld;
return 0;
}
Your program has undefined behavior which means "everything can happen".
You start a new thread which hold a pointer ( this ) to an object. This thread will later call a virtual method which means it needs to use data from the object it points to. The vtable pointer itself is some kind of data of the class. Because you delete your object from the other thread, the pointer ( this ) is simply pointing to a destructed object and accessing data ( vtable ) from an deleted object is undefined behavior.
Your observation is depending on the compiler implementation and maybe also on optimizing level. It is possible, that your compiler rewinds during deconstruction the vtable pointer down to the base class pointer. And as the memory of the object is not overridden from any other content ( which is even undefined! ) you can observe a call to the base function after destruction. But this is nothing you can rely on, as it is not allowed at all to use any object after destruction IF you use data members of the object which here is the vtable pointer.
In a short: Your code contains a bug and everything can happen as it is undefined behavior.
Your code exhibits the Undefined behavior (in your case resulting in Parent::execute call) because of the race condition between thread creation and Child object destruction. To fix it, you can define proper start and stop methods in your Parent class and call stop in Child destructor to prevent it from being destroyed before thread joins.
class Parent
{
public:
Parent(): myThread_() {
std::cout << "Parent CTor" << std::endl;
}
virtual ~Parent() = default;
bool start()
{
std::cout << "start" << std::endl;
if (myThread_.joinable()) {
std::cout << "already started" << std::endl;
return false;
}
myThread_ = std::thread([this]() {
execute();
});
return true;
}
bool stop() {
std::cout << "stop" << std::endl;
if (!myThread_.joinable()) {
std::cout << "not started" << std::endl;
return false;
}
myThread_.join();
return true;
}
virtual void execute() = 0;
private:
std::thread myThread_;
};
class Child : public Parent
{
public:
Child() {
std::cout << "Child CTor" << std::endl;
}
~Child() override {
stop();
}
void execute() override {
std::cout << "Child::execute()" << std::endl;
}
};
int main()
{
std::cout << "Init" << std::endl;
Child * chld = new Child();
chld->start();
std::cout << "Delete" << std::endl;
delete chld;
return 0;
}
I defined Parent::execute as abstract because probably you don't want it to be called at all and in case of another bug, at least you can get
terminate, pure virtual method called
This is nothing whatsoever to do with threads. You can reproduce the whole thing - including Undefined Behaviour - synchronously.
Single-threaded version of your classes:
#include <iostream>
#include <string>
class Parent
{
public:
int a;
Parent() : a(0) {}
virtual ~Parent() {}
virtual void execute() {
std::cout << a << " Parent" << std::endl;
}
};
class Child : public Parent
{
public:
Child() {
a = 1;
}
void execute() override {
std::cout << a << " Child" << std::endl;
}
};
and the single-threaded test cases demonstrating exactly the same behaviour:
int main()
{
Child c;
std::cout << "=== automatic lifetime ===\n";
std::cout << "virtual dispatch: ";
c.execute();
std::cout << "explicit static dispatch: ";
c.Parent::execute();
std::cout << "=== dynamic lifetime ===\n";
Child *pc = new Child;
std::cout << "virtual dispatch: ";
pc->execute();
std::cout << "explicit static dispatch: ";
pc->Parent::execute();
std::cout << "=== undefined behaviour ===\n";
delete pc;
std::cout << "explicit static dispatch: ";
pc->Parent::execute();
std::cout << "virtual dispatch: ";
pc->execute();
}
The last two output statements are swapped, because the last one crashed when I ran it (the penultimate is still UB, but happened not to crash)
=== automatic lifetime ===
virtual dispatch: 1 Child
explicit static dispatch: 1 Parent
=== dynamic lifetime ===
virtual dispatch: 1 Child
explicit static dispatch: 1 Parent
=== undefined behaviour ===
explicit static dispatch: 1 Parent
Segmentation fault (core dumped) ./a.out

how constructor work when it has to create a new object of an other class?

I have this code an i am trying to understand how the compiler works:
#include <iostream>
using namespace std;
class Block
{
int data;
public:
Block(int i = 10)
: data(i)
{
cout << "I just created a Block " << endl;
}
~Block()
{
cout << "I will destroy a Block with " << data << endl;
}
void inc()
{
data++;
}
};
class A
{
Block& block1;
Block block2;
public:
A(Block& blk)
: block1(blk)
, block2(blk)
{
cout << "I just created an A " << endl;
}
A(const A& a)
: block1(a.block1)
, block2(a.block2)
{
cout << "I just created an A by copying but I will also do bad things" << endl;
block1.inc();
block2.inc();
}
~A()
{
cout << "I will destroy an A " << endl;
}
void inc()
{
block1.inc();
block2.inc();
}
};
class Fat
{
A a;
A& ra;
A* pa;
public:
Fat(A& da)
: a(da)
, ra(da)
{
pa = new A(da);
cout << "Fat just created !" << endl;
}
~Fat()
{
delete pa;
cout << "Fat to be destroyed !" << endl;
}
void inc()
{
a.inc();
ra.inc();
pa->inc();
}
};
int main()
{
Block block;
A a(block);
Fat fat(a);
fat.inc();
return 0;
}
when it creates an A object,is creating a new block or it use the existing block?
why isn't running the constructor of block?
the output of the program is :
I just created a Block
I just created an A
I just created an A by copying but I will also do bad things
I just created an A by copying but I will also do bad things
Fat just created !
I will destroy an A
I will destroy a Block with 12
Fat to be destroyed !
I will destroy an A
I will destroy a Block with 12
I will destroy an A
I will destroy a Block with 11
I will destroy a Block with 15
You could have demonstrated this with much simpler code.
#include <iostream>
class Noisy
{
public:
Noisy()
{ std::cout << "Noisy default construct\n"; }
~Noisy()
{ std::cout << "Noisy destroy\n"; }
};
int main()
{
Noisy noisy1;
Noisy noisy2(noisy1);
}
Output
Noisy default construct
Noisy destroy
Noisy destroy
Notice that, apparently, only one object was constructed, but two were destroyed. The reason for this apparent inconsistency is because we are not logging all or our constructors. There is an implicitly generated copy constructor, which we are using to construct noisy2 in this line here:
Noisy noisy2(noisy1);
If we define the copy constructor ourselves,
#include <iostream>
class Noisy
{
public:
Noisy()
{ std::cout << "Noisy default construct\n"; }
Noisy(Noisy const&)
{ std::cout << "Noisy copy construct\n"; }
~Noisy()
{ std::cout << "Noisy destroy\n"; }
};
int main()
{
Noisy noisy1;
Noisy noisy2(noisy1);
}
Output:
Noisy default construct
Noisy copy construct
Noisy destroy
Noisy destroy
You can see that two objects are constructed, just with different constructors. If you do this with your various classes, you should see similar results. Your references will not be logged, neither a constructor or destructor, since they are not objects.
when it creates an A object,is creating a new block or it use the existing block? why isn't running the constructor of block?
Looking at A constructor:
A(Block& blk)
: block1(blk)
, block2(blk)
{
}
block1 is a reference to a Block object. So it referes to the already created blk variable, and it won't create another one. So no constructor is invoked in this case.
That is not true for block2 which is not a reference. In that case indeed a new object Block is created, but using copy constructor.
What you've defined in your Block class is a default constructor.
When a class instance is created starting from another object of the same class, then the copy constructor will be invoked (note: not the default constructor).
The copy constructor is implicitly defined by the compiler unless you define one yourself.
For example:
class Block {
public:
Block(const Block& other) : data(oth.data) {
std::cout << "Invoked copy 'ctor" << std::endl;
}
// ... other stuff
};
That's why your code invokes the default constructor of your class Block only once.

Function Objects vs State

I have used function objects to find out what happens to the object that gets passed, and how it effects the state of the object. Here is a snippet of the test code:
#include <iostream>
//#include <boost/function.hpp>
//using boost::function;
#include <functional>
using std::function;
using std::bind;
struct A {
A() { std::cout << "Creating..." << "\n"; }
void operator()() { call(); }
void call() { std::cout << "Executing call..." << "\n"; }
virtual ~A() { std::cout << "Destroying" << "\n"; }
};
typedef function<void ()> Func;
struct B{
Func f;
B(Func ff) : f(ff) {}
void call() {f();}
};
int main(int argc, char *argv[])
{
{
A a;
B b(a);
for (int i = 0; i < 5; ++i)
b.call();
}
{
A a2;
B b2(bind(&A::call, &a2));
for (int i = 0; i < 5; ++i)
b2.call();
}
return 0;
}
/** Output **
Creating...
Destroying
Destroying
Executing call...
Executing call...
Executing call...
Executing call...
Executing call...
Destroying
Destroying
Creating...
Executing call...
Executing call...
Executing call...
Executing call...
Executing call...
Destroying
*/
When I pass the object with operator () overloaded, there is some multiple calls to destructors; and no objects are being created! So, I can not rely, so to say, on the fidelity of the object state. Does it mean that when I pass a function object (with overloaded operator()) for callback, I should assume that the state of the object is not preserved? And is this, the intended behavior?
On the other hand, callback to a bound member function from inside of an object of another type produces a very stable behavior (I don't know what term to use); i.e. to say, I expected the object state to be preserved; and indeed it is! Is this also an intended behaviour? IOW, is this how functors are generally understood?
PS:
I also checked it with boost::function and boost::bind --- The result is quite the similar. Probably another thread is required to discuss the nuances.
About "no constructors": There are calls to the copy constructor.
Try more instrumenting:
struct A {
A() { std::cout << "Creating..." << "\n"; }
void operator()() { call(); }
A(const A&) { std::cout << "Copying" << "\n"; }
A(A&&) { std::cout << "Moving" << "\n"; } // Assuming C++11
void call() { std::cout << "Executing call..." << "\n"; }
virtual ~A() { std::cout << "Destroying" << "\n"; }
};
About copying:
You hand over the callable by value to B's constructor. It has to be copied.
Bind, it is the intended behavior if you hand in a value. The callable you're handing to bind might be a temporary. Thus, the default behavior is to copy.
You can avoid this, by using a reference wrapper, if you know your callable will survive long enough (as is the case in your code). Try:
int main(int argc, char *argv[])
{
{
A a;
{
B b(a);
}
std::cout << "-------------\n";
B(std::ref(a));
std::cout << "-------------\n";
B(bind(&A::call, a));
std::cout << "-------------\n";
B(bind(&A::call, &a));
std::cout << "-------------\n";
B(bind(&A::call, std::ref(a)));
std::cout << "-------------\n";
}
std::cout << "-------------\n";
return 0;
}
When I pass the object with operator () overloaded, there is some multiple calls to destructors; and no objects are being created!
You are not counting the objects that are constructed using the copy constructor, which is created by the compiler when you don't provide any.
Add a copy constructor to A and you will see the number of calls to the destructor to be the same as the calls to the constructors.
struct A {
A() { std::cout << "Creating..." << "\n"; }
// Add this
A(A const& copy) { std::cout << "Creating..." << "\n"; }
void operator()() { call(); }
void call() { std::cout << "Executing call..." << "\n"; }
virtual ~A() { std::cout << "Destroying" << "\n"; }
};

How to use shared_ptr in a decorator pattern implementation correctly?

I am getting memory leak issues in the following code. I understand there are some flows. But not sure. How to use shared_ptr in these scenarios? And in case I need to add more decorators, say Chocolate-Pista-Icecream, how to pass the pointer correctly such that it will get deleted at the exit?
class AbstractCream
{
public:
virtual void ShowFlavour() = 0;
virtual ~AbstractCream()
{
cout << endl << "AbstractCream-DTOR";
}
};
class IceCream :public AbstractCream
{
public:
void ShowFlavour()
{
cout << "IceCream";
}
~IceCream()
{
cout << endl << "IceCream Dtor";
}
};
class DecoratorCream :public AbstractCream
{
private:
std::shared_ptr<AbstractCream> AbCream;
public:
DecoratorCream(std::shared_ptr<AbstractCream>abs) :AbCream(abs)
{}
void ShowFlavour()
{
AbCream->ShowFlavour();
}
virtual ~DecoratorCream()
{
cout << endl << "DecoratorCream-DTOR";
}
};
class ChocolateCream : public DecoratorCream
{
public:
ChocolateCream(std::shared_ptr<AbstractCream>abs) :DecoratorCream(abs)
{}
void ShowFlavour()
{
cout << "CholocateCream added..";
DecoratorCream::ShowFlavour();
}
~ChocolateCream()
{
cout << endl << "ChocolateCream-DTOR";
}
};
class PistaCream : public DecoratorCream
{
public:
PistaCream(std::shared_ptr<AbstractCream> abs) :DecoratorCream(abs)
{}
void ShowFlavour()
{
cout << "PistaCream added..";
DecoratorCream::ShowFlavour();
}
~PistaCream()
{
cout << endl << "PistaCream-DTOR";
}
};
class StrawberryCream : public DecoratorCream
{
public:
StrawberryCream(std::shared_ptr<AbstractCream> abs) :DecoratorCream(abs)
{}
void ShowFlavour()
{
cout << "StrawberryCream added..";
DecoratorCream::ShowFlavour();
}
~StrawberryCream()
{
cout << endl << "StrawberryCream-DTOR";
}
};
int main()
{
std::shared_ptr <AbstractCream> ice1( new IceCream());
std::shared_ptr <PistaCream> pista1(new PistaCream(ice1));
std::shared_ptr <AbstractCream> ice2(new IceCream());
std::shared_ptr <ChocolateCream>choco1( new ChocolateCream(ice2));
pista1->ShowFlavour();
cout << endl;
choco1->ShowFlavour();
cout << endl;
getchar();
_CrtDumpMemoryLeaks();
return 0;
}
The problem doesn't seem to be the std::shared_ptr<...> use in your classes: that seems to be semantically correct (it is too much code to review in detail, though). Instead, I think your main() is wrong: you try to determine memory leaks at point in time when the objects are still alive. I'm not a Windows program but I'm pretty sure that _CrtDumpMemoryLeak() doesn't know about std::shared_ptr<...> and simply reports newed memory which isn't deleted, yet.
There are a couple of simply ways to change your main() to avoid the problem:
Put the allocation of objects into a block and report memory leaks after the block:
int main() {
{
std::shared_ptr <AbstractCream> ice1( new IceCream());
// ...
}
_CrtDumpMemoryLeaks();
}
Put the code doing the actual work into a separate function and in main() just call this function and report on memory leaks:
int actualMain() {
std::shared_ptr <AbstractCream> ice1( new IceCream());
// ...
}
int main() {
int rc = actualMain();
_CrtDumpMemoryLeaks();
}
Report memory leaks from the destructor of an object which is constructed early, e.g., first thing in main():
struct Reporter { ~Reporter() { _CrtDumpMemoryLeaks(); } };
int main() {
Reporter reporter;
std::shared_ptr <AbstractCream> ice1( new IceCream());
// ...
}
With all three approaches the std::shared_ptr<...>s are destroyed before memory leaks are reported. I'm pretty sure that all of these approaches make the memory leaks go away. My preference would be the use of the third approach.
That said, the way the std::shared_ptr<...> are passed isn't ideal from a performance point of view: increments the reference count each time. When passing it through multiple layers it is unnecessarily bumped up while calling and bumped down when returning from the call. There are multiple ways to fix that problem, too:
The simple approach is to pass the std::shared_ptr<...> as a constant reference:
ChocolateCream(std::shared_ptr<AbstractCream> const& abs)
: DecoratorCream(abs) {
}
It can be argued that the pass by reference inhibits copy elision. However, argument construct can only be elided over one level: when passing the object on to another function it is a named object and the rules for copy elision allow eliding the copy from named objects only for return and throw statements. It may still be reasonable to go that route for the inner-most constructor. Even then, the std::shared_ptr<...> should be moved when passing it on (in that case to the construction of the member variable):
DecoratorCream(std::shared_ptr<AbstractCream> abs)
: AbCream(std::move(abs)) {
}
If you want to pass the argument by value in the other constructors, too, you should, at least, std::move(...) the argument. Doing so should avoid the reference count but it still won't avoid all work as it needs to construct/destroy a std::shared_ptr<...> on each level. However, at least, the synchronized maintenance of the reference count would be avoided.
Since I mentioned a performance problem: stop using std::endl. It doesn't do you much good. In your use it just slows down the program.
class AbstractCream
{
public:
virtual void ShowFlavour() = 0;
virtual ~AbstractCream()
{
cout << endl << "AbstractCream-DTOR";
}
};
class IceCream :public AbstractCream
{
public:
void ShowFlavour()
{
cout << "IceCream";
}
~IceCream()
{
cout << endl << "IceCream Dtor";
}
};
class DecoratorCream :public AbstractCream
{
private:
std::shared_ptr<AbstractCream> AbCream;
public:
DecoratorCream(const std::shared_ptr<AbstractCream> &abs) :AbCream(abs)
{}
void ShowFlavour()
{
AbCream->ShowFlavour();
}
virtual ~DecoratorCream()
{
cout << endl << "DecoratorCream-DTOR";
}
};
class ChocolateCream : public DecoratorCream
{
public:
ChocolateCream(const std::shared_ptr<AbstractCream>& abs) :DecoratorCream(abs)
{}
void ShowFlavour()
{
cout << "CholocateCream added..";
DecoratorCream::ShowFlavour();
}
~ChocolateCream()
{
cout << endl << "ChocolateCream-DTOR";
}
};
class PistaCream : public DecoratorCream
{
public:
PistaCream(const std::shared_ptr<AbstractCream> &abs) :DecoratorCream(abs)
{}
void ShowFlavour()
{
cout << "PistaCream added..";
DecoratorCream::ShowFlavour();
}
~PistaCream()
{
cout << endl << "PistaCream-DTOR";
}
};
class StrawberryCream : public DecoratorCream
{
public:
StrawberryCream(const std::shared_ptr<AbstractCream>& abs) :DecoratorCream(abs)
{}
void ShowFlavour()
{
cout << "StrawberryCream added..";
DecoratorCream::ShowFlavour();
}
~StrawberryCream()
{
cout << endl << "StrawberryCream-DTOR";
}
};
//-------------------dec--------------------------------------------------------------//
struct DummyToLeakCheck
{
public:
~DummyToLeakCheck()
{
_CrtDumpMemoryLeaks();
}
};
int main()
{
DummyToLeakCheck myLeakChecker;
std::shared_ptr <AbstractCream> ice1( new IceCream());
std::shared_ptr <PistaCream> pista1(new PistaCream(ice1));
std::shared_ptr <AbstractCream> ice2(new IceCream());
std::shared_ptr <ChocolateCream>choco1( new ChocolateCream(ice2));
std::shared_ptr <StrawberryCream>straw1(new StrawberryCream(choco1));
pista1->ShowFlavour();
cout << endl;
choco1->ShowFlavour();
cout << endl;
straw1->ShowFlavour();
cout << endl;
getchar();
return 0;
}
Using a Leak-checker as mentioned in the first answer helped correcting the original code.Modified code. Ignoring std::endl as of now, since the purpose of the code is to try out smart pointers in decorator pattern.

C++ const reference member extending lifetime of object

This is related to a question posted yesterday.
class A
{
public:
mutable int x;
A()
{
static int i = 0;
x = i;
i++;
std::cout << " A()" << std::endl;
}
~A()
{
std::cout << "~A()" << std::endl;
}
void foo() const
{
x = 1;
};
};
class B
{
public:
const A & a;
B(const A & a) : a(a)
{
std::cout << " B()" << std::endl;
}
~B()
{
std::cout << "~B()" << std::endl;
}
void doSomething()
{
a.foo();
};
};
int main()
{
B b((A()));
b.doSomething();
}
Now, a's destructor is called before the call to doSomething. However, the call works although the function basically changes a member of A. Is it not the same instance. No other A's are created. I used the static inside A's constructor to keep track of that. Can anyone explain?
This is undefined behavior, so there is no language standard explanation.
However, the destructor of A doesn't do anything to the memory area where x is stored, so if you look there later the value might just still be there. Or if you try to write to the address, the address is still there. You are just not allowed to do that.
Bo is correct.
In addition, you could check the address where 'A' is stored, and that should confirm that that address simply hasn't been reused yet (keep in mind a destructor frees ("releases") the memory, but doesn't traverse the data structure setting all of the bits back to 0; that would be inefficient).
If, for example, you find that A is stored on top of the stack, then you are simply fortunate that your subsequent function call doesn't pass in a parameter, as that would overwrite A's memory region.
Your reference is invalid after ~A() and it is undefined behavior
~A() calls destructors of all members of A in addition
Try so for example
class B
{
public:
const std::string & a;
B(const std::string & a) : a(a)
{
std::cout << " B()" << std::endl;
}
~B()
{
std::cout << "~B()" << std::endl;
}
void doSomething()
{
std::cout << "a = " << a << std::endl;
};
};
int main()
{
B b(std::string("I love C++ so much!"));
b.doSomething();
}
Expanding on Bo's answer.
For a temporary to exist, space will be reserved on the stack. This space is actually reserved as long as the semantics require the temporary to exist, and may then be reuse for something else.
If you were trying to use the memory after it has been reused, you would observe a strange behavior (the very definition of undefined behavior being that anything can happen). As it is, you luck out and the memory is still there, in the state you expect it to.
Example:
#include <iostream>
struct A {
A(): p(0) {}
~A() { if (p) { std::cout << *p << "\n"; } }
int* p;
};
int bar0();
void bar1(int i);
int main() {
A a;
{
int x = 4; a.p = &x;
}
{
int y = bar0(); bar1(y);
}
}
int bar0() { return 7; }
void bar1(int i) { std::cout << i << "\n"; }
Here, the compiler may choose to reuse the space of x for y, or just do anything it wants, and thus you're actually printing garbage.
Here is gcc 4.3.4 (and 4.5.1) output (courtesy of ideone):
7
4
Meaning that the space is not reused with those...