std :: move used,移动构造函数调用但对象仍然有效

时间:2016-05-10 16:54:06

标签: 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& 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)我在移动构造函数中没有移动任何东西,并且2)std::move()在int或double上没有做任何事情,因为它&#移动这些类型比简单复制更昂贵。下面的新代码将类的私有成员变量更新为std :: string而不是double,并在Class&#39;中设置此私有成员变量时正确调用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

2 个答案:

答案 0 :(得分:10)

因为标准是这样说的。

已移动的对象具有有效但未指定的状态。这意味着您仍然可以使用它们,但是您无法确定它们处于什么状态。它们可能看起来就像它们在移动之前所做的那样,取决于最有效的方式是什么?&#34 ;移动&#34;他们的数据。例如,&#34;移动&#34;来自int毫无意义(你必须做额外的工作来重置原始值!)所以&#34;移动&#34;来自int实际上只是一个副本。 double也是如此。

虽然在这种情况下,它与您实际上没有移动任何东西有关。

答案 1 :(得分:3)

在代码示例中,std::move确定调用哪个构造函数。而已。因此c2(std::move(cc))会调用Class的移动构造函数。 Class的移动构造函数对其参数没有任何作用,因此cc不变,并且可以在调用移动构造函数之前使用它。

关于已移出的对象状态的注释和答案中的所有讨论都是关于标准库类型的要求,这些类型将保留为“有效但未指定的状态”( 17.6.5.15,[lib.types.movedfrom])。你对你的类型做什么不受此影响。

编辑:叹息。您编辑了代码并更改了问题。既然您的班级持有std::string而不是float,那么事情就会有所不同,而std::string中的cc对象确实处于“有效但未指定的状态”。