为什么 C++11 移动运算符 (=) 的行为不同
Why is the C++11 move operator (=) behavior different
我已经在 C++11 中测试了 move Semantic。我用一个移动构造函数写了一个class。
class DefaultConstructor
{
public:
DefaultConstructor(std::vector<int> test) :
m_vec(std::forward<std::vector<int>>(test))
{
};
DefaultConstructor(DefaultConstructor &&def) :
m_vec(std::forward<std::vector<int>>(def.m_vec))
{
}
DefaultConstructor& operator=(DefaultConstructor&& def) {
m_vec = std::move(def.m_vec);
return *this;
}
DefaultConstructor& operator=(const DefaultConstructor&) = delete;
DefaultConstructor(DefaultConstructor &) = delete;
std::vector<int> m_vec;
};
我写了一个使用移动语义的主函数。我了解移动语义中发生的事情,它是一个很棒的工具。但是有些行为对我来说无法解释。当我为我调用主函数 DefaultConstructor testConstructor2 = std::move(testConstructor);
时,应该调用 DefaultConstructor& operator=(DefaultConstructor&& def)
。但是 Visual Studio 2015 调用移动构造函数。
int main()
{
std::vector<int> test = { 1, 2, 3, 4, 5 };
DefaultConstructor testConstructor(std::move(test));
DefaultConstructor testConstructor2 = std::move(testConstructor);
DefaultConstructor &testConstructor3 = DefaultConstructor({ 6, 7, 8, 9 });
DefaultConstructor testConstructor4 = std::move(testConstructor3);
swapMove(testConstructor, testConstructor2);
}
好吧,我想也许 = 移动运算符不再需要了。但是我尝试了 SwapMove 函数。此函数调用 = 移动运算符。
template<typename T>
void swapMove(T &a, T &b)
{
T tmp(std::move(a));
a = std::move(b);
b = std::move(tmp);
}
有人可以解释一下这两个调用之间到底有什么区别吗?调用 a = std::move(b);
和 DefaultConstructor testConstructor2 = std::move(testConstructor);
不应该有相同的行为吗?
DefaultConstructor testConstructor2 = std::move(testConstructor);
是构造,不是赋值。它完全类似于 C++11 之前的同类代码中的复制构造与赋值。
语法
DefaultConstructor testConstructor2 = something;
总是调用构造函数,因为对象 testConstructor2
尚不存在。 operator= 只能在已经构造的对象的上下文中调用。
这个:
T foo = bar;
被称为copy-initialization。它通常但不总是等同于:
T foo(bar);
不同的是,后者是对T
构造函数的直接函数调用,而前者试图构造一个从decltype(bar)
到T
的隐式转换序列。因此,存在直接初始化成功但复制初始化可能失败的情况。无论哪种方式,初始化就是初始化:它是构造函数调用,而不是赋值调用。
不过在我们的例子中,这两行是完全等价的:
DefaultConstructor testConstructor2 = std::move(testConstructor);
DefaultConstructor testConstructor2{std::move(testConstructor)};
而且他们都没有调用 DefaultConstructor::operator=
。
我已经在 C++11 中测试了 move Semantic。我用一个移动构造函数写了一个class。
class DefaultConstructor
{
public:
DefaultConstructor(std::vector<int> test) :
m_vec(std::forward<std::vector<int>>(test))
{
};
DefaultConstructor(DefaultConstructor &&def) :
m_vec(std::forward<std::vector<int>>(def.m_vec))
{
}
DefaultConstructor& operator=(DefaultConstructor&& def) {
m_vec = std::move(def.m_vec);
return *this;
}
DefaultConstructor& operator=(const DefaultConstructor&) = delete;
DefaultConstructor(DefaultConstructor &) = delete;
std::vector<int> m_vec;
};
我写了一个使用移动语义的主函数。我了解移动语义中发生的事情,它是一个很棒的工具。但是有些行为对我来说无法解释。当我为我调用主函数 DefaultConstructor testConstructor2 = std::move(testConstructor);
时,应该调用 DefaultConstructor& operator=(DefaultConstructor&& def)
。但是 Visual Studio 2015 调用移动构造函数。
int main()
{
std::vector<int> test = { 1, 2, 3, 4, 5 };
DefaultConstructor testConstructor(std::move(test));
DefaultConstructor testConstructor2 = std::move(testConstructor);
DefaultConstructor &testConstructor3 = DefaultConstructor({ 6, 7, 8, 9 });
DefaultConstructor testConstructor4 = std::move(testConstructor3);
swapMove(testConstructor, testConstructor2);
}
好吧,我想也许 = 移动运算符不再需要了。但是我尝试了 SwapMove 函数。此函数调用 = 移动运算符。
template<typename T>
void swapMove(T &a, T &b)
{
T tmp(std::move(a));
a = std::move(b);
b = std::move(tmp);
}
有人可以解释一下这两个调用之间到底有什么区别吗?调用 a = std::move(b);
和 DefaultConstructor testConstructor2 = std::move(testConstructor);
不应该有相同的行为吗?
DefaultConstructor testConstructor2 = std::move(testConstructor);
是构造,不是赋值。它完全类似于 C++11 之前的同类代码中的复制构造与赋值。
语法
DefaultConstructor testConstructor2 = something;
总是调用构造函数,因为对象 testConstructor2
尚不存在。 operator= 只能在已经构造的对象的上下文中调用。
这个:
T foo = bar;
被称为copy-initialization。它通常但不总是等同于:
T foo(bar);
不同的是,后者是对T
构造函数的直接函数调用,而前者试图构造一个从decltype(bar)
到T
的隐式转换序列。因此,存在直接初始化成功但复制初始化可能失败的情况。无论哪种方式,初始化就是初始化:它是构造函数调用,而不是赋值调用。
不过在我们的例子中,这两行是完全等价的:
DefaultConstructor testConstructor2 = std::move(testConstructor);
DefaultConstructor testConstructor2{std::move(testConstructor)};
而且他们都没有调用 DefaultConstructor::operator=
。