Reputation: 1971
When running the following code on gcc 8 (https://wandbox.org/, with "g++ prog.cc -Wall -Wextra -std=c++1z"):
#include <iostream>
class B{
public:
B(): copy(false){ std::cout << "B-constructed" << std::endl;}
B(const B& b): copy(true){ std::cout << "B-copy-constructed" << std::endl; }
~B(){ std::cout << (copy?"B-destructed":"B-(copy)-destructed") << std::endl;}
bool copy;
};
class A{
public:
A(B b): bref(b){std::cout << "A-constructed" << std::endl;}
~A() {std::cout << "A-destructed" << std::endl;}
B &bref;
};
void f(){
B b;
A a(b);
std::cout << "f over" << std::endl;
}
int main()
{
f();
std::cout << "main over" << std::endl;
return 0;
}
the following output is yielded:
B-constructed
B-copy-constructed
A-constructed
B-destructed
f over
A-destructed
B-(copy)-destructed
main over
The order of object destructions seems unusual. It is as if the lifetime of the constructor's parameter is extended. Does the standard say anything about binding member references to constructor parameters?
I don't think that this quote from the standard applies, as the parameter is not a temporary object (however I do not know the definition of a "temporary expression"):
A temporary expression bound to a reference member in a mem-initializer is ill-formed. [ Example:
struct A {
A() : v(42) { } // error
const int& v;
};
—end example ]
Upvotes: 1
Views: 714
Reputation: 73366
Your destructor has a logical error, since you print that a copy is destructed when copy
is wrong.
Change this:
~B(){ std::cout << (copy?"B-destructed":"B-(copy)-destructed") << std::endl;}
to this:
~B(){ std::cout << (copy?"B-(copy)-destructed":"B-destructed") << std::endl;}
which now outputs:
B-constructed
B-copy-constructed
A-constructed
B-(copy)-destructed
f over
A-destructed
B-destructed
main over
nice and clear (Order of member constructor and destructor calls).
Does the standard say anything about binding member references to constructor parameters?
Similarly, 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 glvalue that refers to the original object may be used but only in limited ways. For an object under construction or destruction, see [class.cdtor]. Otherwise, such a glvalue refers to allocated storage ([basic.stc.dynamic.deallocation]), and using the properties of the glvalue that do not depend on its value is well-defined.
Upvotes: 1