我很困惑何时调用移动构造函数和复制构造函数。 我已经阅读了以下资料来源:
Move constructor is not getting called in C++0x
Move semantics and rvalue references in C++11
所有这些来源要么过于复杂(我只想要一个简单的例子),要么只展示如何编写移动构造函数,而不是如何调用它。我写了一个简单的问题更具体:
const class noConstruct{}NoConstruct;
class a
{
private:
int *Array;
public:
a();
a(noConstruct);
a(const a&);
a& operator=(const a&);
a(a&&);
a& operator=(a&&);
~a();
};
a::a()
{
Array=new int[5]{1,2,3,4,5};
}
a::a(noConstruct Parameter)
{
Array=nullptr;
}
a::a(const a& Old): Array(Old.Array)
{
}
a& a::operator=(const a&Old)
{
delete[] Array;
Array=new int[5];
for (int i=0;i!=5;i++)
{
Array[i]=Old.Array[i];
}
return *this;
}
a::a(a&&Old)
{
Array=Old.Array;
Old.Array=nullptr;
}
a& a::operator=(a&&Old)
{
Array=Old.Array;
Old.Array=nullptr;
return *this;
}
a::~a()
{
delete[] Array;
}
int main()
{
a A(NoConstruct),B(NoConstruct),C;
A=C;
B=C;
}
目前A,B和C都有不同的指针值。我希望A有一个新指针,B有C的旧指针,C有空指针。
有点偏离主题,但如果有人可以建议我可以详细了解这些新功能的文档,我将不胜感激,可能不需要再问更多问题。
答案 0 :(得分:27)
调用移动构造函数:
std::move(something)
std::forward<T>(something)
且T
不是左值引用类型时(在“完美转发”的模板编程中很有用)这不是一个完整的清单。请注意,如果参数具有类类型(不是引用),则“对象初始值设定项”可以是函数参数。
a RetByValue() {
a obj;
return obj; // Might call move ctor, or no ctor.
}
void TakeByValue(a);
int main() {
a a1;
a a2 = a1; // copy ctor
a a3 = std::move(a1); // move ctor
TakeByValue(std::move(a2)); // Might call move ctor, or no ctor.
a a4 = RetByValue(); // Might call move ctor, or no ctor.
a1 = RetByValue(); // Calls move assignment, a::operator=(a&&)
}
答案 1 :(得分:4)
首先,您的复制构造函数已损坏。从对象复制和复制到对象都将指向相同的Array
,并且当它们超出范围时都会尝试delete[]
,从而导致未定义的行为。要修复它,请复制该数组。
a::a(const a& Old): Array(new int[5])
{
for( size_t i = 0; i < 5; ++i ) {
Array[i] = Old.Array[i];
}
}
现在,移动赋值没有按照你想要的那样执行,因为两个赋值语句都是从左值赋值而不是使用rvalues。对于要执行的移动,您必须从rvalue移动,或者它必须是可以将左值视为rvalue的上下文(例如函数的return语句)。
要获得所需效果,请使用std::move
创建右值参考。
A=C; // A will now contain a copy of C
B=std::move(C); // Calls the move assignment operator
答案 2 :(得分:0)
请记住,可能会发生复制省略。如果通过将-fno-elide-constructors
标志传递给编译器来禁用它,则构造函数可能会被执行。
您可以在这里阅读有关内容:https://www.geeksforgeeks.org/copy-elision-in-c/