为什么成员初始值设定项在移动时会调用额外的构造函数调用?
Why does member initilizer invoke extra constructor call when moved?
当在具有移动构造函数的 class 中使用成员初始值设定项时,在移动封闭的 class 时调用已初始化成员的构造函数。为什么会这样?请提供标准参考。我根据下面的示例结果猜测发生了什么。
另外,在稍微不同的情况下,如果初始化的成员是普通旧数据类型,为什么不调用成员的构造函数?
此外,关于成员初始值设定项和移动构造函数的最佳实践是什么?
#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));
}
结果:
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
为什么使用成员初始值设定项会为 C 调用另一个构造函数调用?
为什么使用成员初始值设定项会导致 Foo 析构函数 运行 C->do_stuff()?
我的问题是,在实际构造函数(在本例中为移动构造函数)获得 运行 之前,成员初始值设定项针对所有构造函数类型进行评估。对吗?
我特别希望标准中的参考资料能够验证或反驳我的猜测。
当定义 MEMBER_INIT
时,移动构造函数使用 in-class 初始化程序执行 ptr
初始化并变为
Foo(Foo && rhs): ptr{make_unique<C>()}
否则默认初始化。
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;
基本上你忘记了通过移动手动初始化 ptr
字段:
Foo(Foo && rhs): ptr{::std::move(rhs.ptr)}
当在具有移动构造函数的 class 中使用成员初始值设定项时,在移动封闭的 class 时调用已初始化成员的构造函数。为什么会这样?请提供标准参考。我根据下面的示例结果猜测发生了什么。
另外,在稍微不同的情况下,如果初始化的成员是普通旧数据类型,为什么不调用成员的构造函数?
此外,关于成员初始值设定项和移动构造函数的最佳实践是什么?
#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));
}
结果:
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
为什么使用成员初始值设定项会为 C 调用另一个构造函数调用? 为什么使用成员初始值设定项会导致 Foo 析构函数 运行 C->do_stuff()?
我的问题是,在实际构造函数(在本例中为移动构造函数)获得 运行 之前,成员初始值设定项针对所有构造函数类型进行评估。对吗?
我特别希望标准中的参考资料能够验证或反驳我的猜测。
当定义 MEMBER_INIT
时,移动构造函数使用 in-class 初始化程序执行 ptr
初始化并变为
Foo(Foo && rhs): ptr{make_unique<C>()}
否则默认初始化。
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;
基本上你忘记了通过移动手动初始化 ptr
字段:
Foo(Foo && rhs): ptr{::std::move(rhs.ptr)}