When a member initializer is used in a class that has a move constructor the initilized member's constructor gets called when the enclosing class is moved. Why does this happen? Please provide references to the standard. I have a guess as to what's happening that I give with the example results below.
Also, in slightly different scenrio, why doesn't the member's constructor get called if the initialized member is a plain-old-data type?
Also, what are best practices concerning member initializers and move constructors?
#include <bits/stdc++.h>
using namespace std;
struct C {
void do_stuff(){cout<<"stuff";}
C(){cout<<"C ctor"<<endl;}
~C(){cout<<"C DTOR"<<endl;}
};
struct Foo {
ifdef MEMBER_INIT
Foo() {cout<<"Foo ctor"<<endl;};
#else
Foo() : ptr(new C) {cout<<"Foo ctor"<<endl;};
#endif
Foo(Foo &) = delete;
Foo & operator=(Foo &) = delete;
Foo & operator=(Foo &&) = delete;
Foo(Foo && rhs){cout<<"Foo MOVE ctor"<<endl; rhs.ptr.swap(this->ptr); }
~Foo(){cout << "Foo DTOR "; if(ptr) ptr->do_stuff(); cout<<endl; }
#ifdef MEMBER_INIT
unique_ptr<C> ptr = make_unique<C>();
#else
unique_ptr<C> ptr;
#endif
};
int main()
{
Foo f;
Foo f2(move(f));
}
RESULTS:
g++ -std=c++14 x.cc && ./a.out
C ctor
Foo ctor
Foo MOVE ctor
Foo DTOR stuff
C DTOR
Foo DTOR
g++ -DMEMBER_INIT -std=c++14 x.cc && ./a.out
C ctor
Foo ctor
C ctor
Foo MOVE ctor
Foo DTOR stuff
C DTOR
Foo DTOR stuff
C DTOR
Why does using the member initializer invoke another constructor call for C? Why does using the member initializer cause the Foo destructor to run C->do_stuff()?
My quess is that member initializers get evaluated for ALL constructor types before the actual constructor (in this case a move constructor) gets run. Is that correct?
I would specifically like references in the standard that verify or contradict my guess.
答案 0 :(得分:0)
When MEMBER_INIT
is defined move constructor performs ptr
initialization using in-class initializer and becomes
Foo(Foo && rhs): ptr{make_unique<C>()}
Otherwise it is default-initialized.
15.6.2 Initializing bases and members [class.base.init]
9 In a non-delegating constructor, if a given potentially constructed subobject is not designated by a mem-initializer-id (including the case where there is no mem-initializer-list because the constructor has no ctor-initializer), then
…
the entity is initialized from its default member initializer as specified in 11.6;
Basically you forgot to actually manually initialize ptr
field by moving:
Foo(Foo && rhs): ptr{::std::move(rhs.ptr)}