我在visual studio 11上尝试了一些新的C ++ 11功能,从移动构造函数开始。我写了一个名为“MyClass”的简单类,其中包含一个移动构造函数:
class MyClass
{
public:
explicit MyClass( int aiCount )
: mpiSize( new int( aiCount ) ),
miSize2( aiCount)
{
}
MyClass( MyClass&& rcOther )
: mpiSize( rcOther.mpiSize )
, miSize( *rcOther.mpiSize )
{
rcOther.mpiSize = 0;
rcOther.miSize = 0;
}
~MyClass()
{
delete mpiSize;
}
private:
int *mpiSize;
int miSize2;
};
我在这里有问题:
答案 0 :(得分:25)
MSVC ++在标准的最终版本发布之前实现了移动构造函数。在标准MSVC ++的实现版本的基础上,生成默认移动构造函数的规则比标准的最终版本更严格。有关详细信息,请参见此处:Why is this code trying to call the copy constructor?(具体为this answer及其评论)。这已经并且不会在Visual Studio 11中修复,出于某种未知的愚蠢原因,因为它们还有其他优先事项。
不,您需要在std::move
的成员上调用rcOther
,并使用垂死对象(您错误命名为miSize
)中的相应成员初始化成员:< / p>
MyClass( MyClass&& rcOther )
: mpiSize( std::move(rcOther.mpiSize) )
, miSize2( std::move(rcOther.miSize2) )
{
rcOther.mpiSize = 0;
}
它对int
和int*
等内置类型没有什么影响,但肯定会对用户定义的类型产生影响。
std::move
只返回转换为T&&
rvalue-reference的参数,以便正确的构造函数(移动构造函数,T(T&&)
)为每个子对象调用。如果您不对临终对象的成员使用std::move
,则会将它们视为T&
,并且将调用子对象(T(T&)
)的复制构造函数而不是移动构造函数。这是非常糟糕的,几乎是你编写移动构造函数的全部目的。
3.你正在做一些不必要的事情,比如将整数设置为0.你只需要将指针设置为0,这样delete
它就不会删除你创建的新对象的资源。
此外,如果这不是一个教学练习,您可能需要考虑使用std::unique_ptr
而不是管理自己对象的生命周期。这样你甚至不必为你的类编写析构函数。请注意,如果您这样做,则必须使用std::move
从移动构造函数中的垂死成员初始化成员。
答案 1 :(得分:12)
如果你不这样做,编译器会生成一个移动构造函数 - 一个时尚之后。但是,编译器无法猜测您的动机,因此它不知道您的类中的指针是什么。特别是,它不知道指针赋予了内存的所有权,需要被淘汰。
移动构造函数是正确的 1 但是类的其余部分没有,你违反了rule of three:你的类需要一个合适的复制构造函数和复制赋值运算符。
编写移动构造函数的更好方法如下:
MyClass(MyClass&& rcOther)
: mpiSize(std::move(rcOther.mpiSize))
, miSize2(std::move(rcOther.miSize2))
{
rcOther.mpiSize = 0;
}
两条评论:
rcOther.mpiSize
?虽然这没有错,但它也毫无意义并且具有误导性。 但更好的方法是依靠已有的设施。在这种情况下,您需要为内存所有权建模。裸指针做得不好,你应该使用std::unique_ptr
代替。这样,您不需要实现析构函数也不需要移动构造函数,因为自动生成的方法是正确的。
1 警告:请参阅Seth的答案,以获得更好的解释,提及std::move
(在这种特殊情况下,这是一个无操作)。 / p>
答案 2 :(得分:1)
从C ++ 14开始,您可以利用std::exchange()
便捷函数模板来定义move构造函数。这可能会导致更简洁的move构造函数定义:
MyClass(MyClass&& other) noexcept:
mpiSize(std::exchange(other.mpiSize, nullptr)),
miSize2(std::exchange(other.miSize2, 0))
{}
std::exchange(other.mpiSize, nullptr)
用other.mpiSize
替换nullptr
的值,但返回替换前的值other.mpiSize
。