C++ 使用了move,调用了move构造函数,但对象仍然有效
有人能解释为什么通过std::move传递给新对象的原始对象在之后仍然有效吗C++ 使用了move,调用了move构造函数,但对象仍然有效,c++,move,rvalue-reference,C++,Move,Rvalue Reference,有人能解释为什么通过std::move传递给新对象的原始对象在之后仍然有效吗 #include <iostream> class Class { public: explicit Class(const double& tt) : m_type(tt) { std::cout << "defaultish" << std::endl; }; explicit Class(const Class&am
#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;
}
我希望对cc.set和cc.print的调用会失败
更新
感谢下面的答案,我们已经确定1 I没有在move构造函数中移动任何内容,2 std::move on int或double没有任何作用,因为移动这些类型比简单地复制要昂贵。下面的新代码将类的私有成员变量更新为std::string类型而不是double类型,并在类的move构造函数中设置此私有成员变量时正确调用std::move,从而生成一个输出,显示std::move如何导致有效但未指定的状态
因为标准是这么说的 从对象移动的对象具有有效但未指定的状态。这意味着您仍然可以使用它们,但无法确定它们将处于何种状态。它们看起来可能与移动前一样,这取决于从中移出数据的最有效方式。例如,从int移动没有任何意义,您必须做额外的工作来重置原始值!所以从int开始的移动实际上只是一个拷贝。双重身份也是如此
虽然在这种情况下,它更多的是因为你实际上没有移动任何东西。因为标准上这么说 从对象移动的对象具有有效但未指定的状态。这意味着您仍然可以使用它们,但无法确定它们将处于何种状态。它们看起来可能与移动前一样,这取决于从中移出数据的最有效方式。例如,从int移动没有任何意义,您必须做额外的工作来重置原始值!所以从int开始的移动实际上只是一个拷贝。双重身份也是如此 虽然在本例中,它更多地与您实际上没有移动任何东西有关。在代码示例中,std::move确定调用哪个构造函数。没别的了。所以c2std::movecc调用类的move构造函数。类的move构造函数不会对其参数做任何修改,因此cc是不变的,可以像调用move构造函数之前一样使用它 注释和答案中关于已从中移动的对象状态的所有讨论都是关于标准库类型的要求,这些类型将保持在有效但未指定的状态17.6.5.15[lib.types.movedfrom]。你对你的类型所做的不会受到影响 编辑:叹气。您编辑了代码并更改了问题。既然您的类持有std::string而不是float,情况就不同了,而且cc中的std::string对象确实处于有效但未指定的状态。在代码示例中,std::move确定调用哪个构造函数。没别的了。所以c2std::movecc调用类的move构造函数。类的move构造函数不会对其参数做任何修改,因此cc是不变的,可以像调用move构造函数之前一样使用它 注释和答案中关于已从中移动的对象状态的所有讨论都是关于标准库类型的要求,这些类型将保持在有效但未指定的状态17.6.5.15[lib.types.movedfrom]。你对你的类型所做的不会受到影响
编辑:叹气。您编辑了代码并更改了问题。现在,您的类持有的是std::string而不是float,情况就不同了,cc中的std::string对象确实处于有效但未指定的状态。根据经验,您可以对“已移动自”对象调用成员函数,该对象没有包括赋值和销毁在内的先决条件。您能解释一下您实际上没有移动任何内容的语句吗?这是因为我忘了删除初始值设定项列表吗?@Wond3rBoi您在移动计算器中使用了m_typeval.m_type而不是m_typestd::moveval.m_type。但是,这样做实际上不会对double做任何事情,正如这个答案中所解释的。好的,这是有意义的…如果我将成员变量改为std::string而不是double,并更新对m_typestd::moveval.m_type的调用,那会更有意义。根据经验,您可以对“已移动自”对象调用成员函数,该对象没有包括赋值和销毁在内的先决条件。您能解释一下您实际上没有移动任何内容的语句吗?这是因为我忘了删除初始值设定项列表吗?@Wond3rBoi您在移动计算器中使用了m_typeval.m_type而不是m_typestd::moveval.m_type。但是,这样做实际上对double没有任何作用,正如这个答案中所解释的。好的,这是有意义的……如果我将成员变量更改为std::string而不是double,并更新对m_typestd::moveval.m_type的调用,那会更有意义。
defaultish
move: 3.2
print: 3.2
print: 4
#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