简体   繁体   中英

std::move used, move constructor called but object still valid

Can someone explain why the original object that is passed to a new object via std::move is still valid afterwards?

#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;
}

It outputs the following:

defaultish
move: 3.2
print: 3.2
print: 4

I would expect the calls to cc.set() and cc.print() to fail...

UPDATE Thanks to answers below, we've identified that 1) I wasn't moving anything in the move constructor, and 2) std::move() on an int or double doesn't do anything because it's more expensive to move these types than to simply copy. The new code below updates the class's private member variable to be of type std::string instead of a double, and properly calls std::move when setting this private member variable in the Class' move constructor, resulting in an output that shows how a std::move results in a valid but unspecified state

#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;
}

And finally the output:

defaultish
move: 3.2
print: 3.2
print: 
print: 4.0

Because the standard says so.

Moved-from objects have a valid but unspecified state . That means you can still use them, but you can't be sure what state they'll be in. They could look just as they did before the move, depending on what is the most efficient way to "move" data out of them. For example, "moving" from an int makes no sense (you'd have to do extra work to reset the original value!) so a "move" from an int is actually only ever going to be a copy. The same is true of a double .

Although in this case it's got more to do with the fact that you didn't actually move anything.

In the code example, std::move determines which constructor gets called. Nothing more. So c2(std::move(cc)) calls the move constructor for Class . The move constructor for Class doesn't do anything to its argument, so cc is unchanged, and it can be used just as it could have before the call to the move constructor.

All the talk in comments and answers about the state of an object that has been moved from is about the requirements on standard library types, which will be left in a "valid but unspecified state" (17.6.5.15, [lib.types.movedfrom]). What you do with your types is not affected by that.

EDIT: sigh. You edited the code and changed the question. Now that your class holds a std::string instead of a float things are different, and the std::string object in cc is, indeed, in a "valid but unspecified state".

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM