Reputation: 21
Suppose I have a class
class A { public: A(int i); ~A(); private: B b; // Want <- this guy to be constructed with i in A's constructor! };I want b to be constructed in the constructor with particular parameters that aren't known until A is constructed. If I were to do the following in A's constructor:
A::A(int i) { B b(i); // Or even if I try to do b = B::B(i); }
I notice that b get's allocated twice on the stack! aghghg.
Then I found out that what I can do in A's constructor is:
A::A() : b(B::B(7)) { }
And b only gets allocated on the stack once!
But this is pretty clunky. Anyone got a better idea? Remember, the constructor should only be called once!
Is this the standard way of allocating objects NON-dynamically with important parameters? What if we can shove b's construction into that fancy argument list thing!? You're forced to either dynamically allocate, or construct TWICE on the stack!
Bonus Question: When does b get deallocated? Is it after or right before A's destructor
Upvotes: 2
Views: 204
Reputation: 12901
does
A::A() : b(7) { }
not work?
Edit: I'm at work, so I'll do a more comprehensive edit later using some profile stuff to see what gcc does w.r.t. deallocation. I suspect that nobar is right and all deallocation happens at once.
b(B::B(7))
works as well as b(7)
because B::B(7)
creates a temporary B
variable. b
is then copy-constructed from that temporary. A decent optimizing compiler should be able to reduce the second case to the first but:
b(7)
is more idiomatic -- other c++ programmers will recognize is more easilyB
is not copy-constructible, or expensive to copy-construct, you may not want to deal with the added overhead if, like most, you turn off optimizations for debugging.Upvotes: 2
Reputation: 54859
It only takes a small modification to your program to demonstrate the order of construction and destruction.
#include <iostream>
using std::cerr;
class B
{
public:
B( int ) { cerr<<"B()\n"; ;}
~B() { cerr<<"~B()\n"; }
};
class A
{
B b;
public:
A( int i ) : b(i) { cerr<<"A()\n"; }
~A() { cerr<<"~A()\n"; }
};
int main()
{
A a(7);
}
Here's the output:
$ make destructor_order && ./destructor_order
B()
A()
~A()
~B()
Upvotes: 0
Reputation: 52149
I'm sorry to say but you have it all wrong.
What you need to do is to pick up a good beginner's C++ book. This is such a fundamental part of the language that if you don't understand this you will struggle when dealing with non-trivial C++ code.
That being said, when an object is about to be created, all subobjects will be created first. If you need to pass parameters to those subobject constructors, you need to create what's called an initializer list:
A::A(int i) : b(i) {}
The stuff that follows the colon and before the first brace is the initializer list. Only constructors can have them. What's going on here is that we pass the value of i
to the b
subobject's constructor. This happens before the constructor for A
is called!
So for your case, the order of construction is:
b
subobjectA
object itselfThe order of destruction is the complete opposite process.
Upvotes: 7