我有两段类似的代码。第一个版本意外地调用了默认构造函数,而第二个版本没有。正如预期的那样,它们都分别调用了move运算符/move构造函数。
class MyResource
{
public:
MyResource() : m_data(0) { std::cout << "Default Ctor" << std::endl; }
MyResource(int data) : m_data(data) { std::cout << "Int Ctor" << std::endl; }
MyResource(MyResource const& other) = delete;
MyResource& operator=(MyResource const& other) = delete;
MyResource(MyResource&& other) noexcept : m_data(other.m_data) { std::cout << "Move Ctor" << std::endl; }
MyResource& operator=(MyResource&& other) noexcept { std::cout << "Move Op" << std::endl; m_data = other.m_data; return *this; }
~MyResource() { std::cout << "Dtor" << std::endl; }
private:
int m_data = 0;
};
class MyWrapper
{
public:
MyWrapper(MyResource&& resource)
// : m_resource(std::move(resource)) // Version 2
{
// m_resource = std::move(resource); // Version 1
}
private:
MyResource m_resource;
};
我的测试用途是:
MyWrapper* wrapper = new MyWrapper(MyResource(1));
delete wrapper;
对于版本1,我得到:
Int Ctor
默认Ctor
移动操作
Dtor
Dtor
当版本2输出时:
Int Ctor
移动Ctor
Dtor
Dtor
这种差异背后的原因是什么
为什么版本1调用默认构造函数?
在运行构造体之前初始化成员。一个简单得多的例子:
#include <iostream>
struct foo {
foo(int) { std::cout << "ctrn";}
foo() { std::cout << "default ctrn";}
void operator=(const foo&) { std::cout << "assignmentn"; }
};
struct bar {
foo f;
bar(int) : f(1) {}
bar() {
f = foo();
}
};
int main() {
bar b;
std::cout << "---------n";
bar c(1);
}
输出:
default ctr
default ctr
assignment
---------
ctr
无法初始化构造函数主体中的成员!如果未在成员初始值设定项列表中或作为类内初始值设定值设定项提供初始值设定,则默认构造f
。在构造函数体中,您只能分配给已初始化的成员。