为什么成员初始值设定项在移动时会调用额外的构造函数调用?

问题描述 投票:0回答:1

当在具有移动构造函数的类中使用成员初始值设定项时,在移动封闭类时将调用已启用成员的构造函数。为什么会这样?请提供该标准的参考。我猜测下面的示例结果给出了什么。

另外,在稍微不同的场景中,如果初始化成员是普通旧数据类型,为什么不调用成员的构造函数?

另外,关于成员初始化器和移动构造器的最佳实践是什么?

#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()?

我的问题是,在实际构造函数(在本例中为移动构造函数)运行之前,会为所有构造函数类型计算成员初始值设定项。那是对的吗?

我特别喜欢标准中的引用来验证或反驳我的猜测。

c++ constructor language-lawyer move-semantics move-constructor
1个回答
0
投票

当定义MEMBER_INIT时,移动构造函数使用类内初始化程序执行ptr初始化并变为

Foo(Foo && rhs): ptr{make_unique<C>()}

否则,它是默认初始化的。

15.6.2初始化基数和成员[class.base.init] 9在非委托构造函数中,如果给定的可能构造的子对象未由mem-initializer-id指定(包括没有mem-initializer-list的情况,因为构造函数没有ctor-initializer),那么 ... 实体从其默认成员初始化程序初始化,如11.6中所述;

基本上你忘了通过移动实际手动初始化ptr字段:

Foo(Foo && rhs): ptr{::std::move(rhs.ptr)}
© www.soinside.com 2019 - 2024. All rights reserved.