std::使用了move,调用了move构造函数,但对象仍然有效
std::move used, move constructor called but object still valid
有人能解释为什么通过std::move传递给新对象的原始对象在之后仍然有效吗?
#include <iostream>
class Class
{
public:
explicit Class(const double& tt) : m_type(tt)
{
std::cout << "defaultish" << std::endl;
};
explicit Class(const Class& val) :
m_type(val.m_type)
{
std::cout << "copy" << std::endl;
};
explicit Class(Class&& val) :
m_type(val.m_type)
{
m_type = val.m_type;
std::cout << "move: " << m_type << std::endl;
};
void print()
{
std::cout << "print: " << m_type << std::endl;
}
void set(const double& tt)
{
m_type = tt;
}
private:
double m_type;
};
int main ()
{
Class cc(3.2);
Class c2(std::move(cc));
c2.print();
cc.set(4.0);
cc.print();
return 0;
}
它输出以下内容:
defaultish
move: 3.2
print: 3.2
print: 4
我预计对cc.set()和cc.print()的调用会失败。。。
更新多亏了下面的答案,我们发现1)我没有在move构造函数中移动任何东西,2)int或double上的std::move()
没有做任何事情,因为移动这些类型比简单地复制更昂贵。下面的新代码将类的私有成员变量更新为std::string类型,而不是double类型,并在class的move构造函数中设置此私有成员变量时正确调用std::move,从而生成一个输出,显示std::move如何导致有效但未指定的状态
#include <iostream>
#include <string>
class Class
{
public:
explicit Class(const std::string& tt) : m_type(tt)
{
std::cout << "defaultish" << std::endl;
};
explicit Class(const Class& val) :
m_type(val.m_type)
{
std::cout << "copy" << std::endl;
};
explicit Class(Class&& val) : m_type(std::move(val.m_type))
{
std::cout << "move: " << m_type << std::endl;
};
void print()
{
std::cout << "print: " << m_type << std::endl;
}
void set(const std::string val )
{
m_type = val;
}
private:
std::string m_type;
};
int main ()
{
Class cc("3.2");
Class c2(std::move(cc));
c2.print( );
cc.print();
cc.set( "4.0" );
cc.print();
return 0;
}
最后输出:
defaultish
move: 3.2
print: 3.2
print:
print: 4.0
因为标准是这么说的。
从对象中移动具有有效但未指定的状态。这意味着你仍然可以使用它们,但你不能确定它们会处于什么状态。它们可能看起来和移动前一样,这取决于从中"移动"数据的最有效方式。例如,从int
"移动"是没有意义的(你必须做额外的工作才能重置原始值!),所以从int
"移动"实际上只是一个副本。double
也是如此。
尽管在这种情况下,更多的是因为你实际上没有移动任何东西。
在代码示例中,std::move
决定调用哪个构造函数。没什么了。因此c2(std::move(cc))
调用了Class
的move构造函数。Class
的move构造函数不对其参数执行任何操作,因此cc
保持不变,并且可以像调用move构造函数之前一样使用它。
评论和答案中关于已移动对象状态的所有讨论都是关于标准库类型的要求,这些类型将处于"有效但未指定的状态"(17.6.5.15,[lib.types.movedfrom])。您对类型的处理不受此影响。
编辑:叹气。您编辑了代码并更改了问题。现在,您的类持有std::string
而不是float
,情况有所不同,并且cc
中的std::string
对象确实处于"有效但未指定的状态"。
- 返回一个带有 std::move 的对象并链接函数
- 当 std::move 与 C 样式数组或不移动对象时会发生什么
- 如何在没有 std::move 的情况下移动临时对象
- 在返回语句中构造对象时,std::move() 是否有助于或阻止 RVO?
- 为什么 std::move 适用于常量对象
- 更改对象的类:可以使用 std::move 吗?
- 如果对象在同一层次结构中,-Wreturn-std-move clang 警告是否正确
- 为什么将临时对象作为参数传递需要 std::move?
- 在 std::move 之后使用对象不会导致编译错误
- 是否可以将 std::move 对象移出函数?(C++11).
- 将只有move构造函数的对象推回到向量
- std::使用了move,调用了move构造函数,但对象仍然有效
- 如果在没有move构造函数的情况下移动对象,会发生什么
- 为什么我们可以在const对象上使用std::move
- C++ 返回指针与返回带有 std::move 的本地对象
- 使用 "new ClassType(std::move(/*class_object*/))" 在自由存储中构造对象
- 为什么在 const 对象上调用 std::move 在传递给另一个对象时会调用复制构造函数
- 当将昂贵的对象存储在一对中时,是否有必要进行 std::move
- 有没有办法使用 move 而不是复制语义将函数返回值(对象)包装在 Python 中
- copy-/move-constructors的奇怪行为以及如何返回大对象?