1

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 ]

Community
  • 1
  • 1
user42768
  • 1,951
  • 11
  • 22
  • 1
    You mixed up the strings in `~B`: if it is a copy, say it is normally destructed, if not, say it is copy-destructed – king_nak Aug 25 '17 at 11:53
  • So what is the question then? What do you think is wrong with the order of construction/destruction, after this is fixed? – king_nak Aug 25 '17 at 11:55
  • Now the order seems fine. However, the question that remains is whether the standard says anything about binding member references to constructor parameters. – user42768 Aug 25 '17 at 11:57
  • Does http://eel.is/c++draft/basic.life#7 explain this behaviour (a reference bound to an object whose lifetime ended)? – user42768 Aug 25 '17 at 12:07

1 Answers1

1

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.

Source

gsamaras
  • 71,951
  • 46
  • 188
  • 305
  • I apologize for my mistake. Yes, the order now seems correct. However, does the standard mention anything about binding member references to constructor parameters? – user42768 Aug 25 '17 at 11:58
  • Sure, no problem. I corrected my question because of the comment received from @king_nak before seeing your answer. – user42768 Aug 25 '17 at 12:01
  • I found this: http://eel.is/c++draft/basic.life#7. I think it explains what happens when referencing an object whose lifetime ended. – user42768 Aug 25 '17 at 12:09