Home > Enterprise >  move ctor of std::string does not work properly?
move ctor of std::string does not work properly?

Time:11-20

Why the msg is not being modified after the call to std::move(msg)?

int main()
{
    std::string msg( "Error!" );

    std::cout << "before try-catch: " << msg << '\n';

    try
    {
        throw std::invalid_argument( std::move( msg ) );
    }
    catch ( const std::invalid_argument& ia )
    {
        std::cerr << ia.what( ) << '\n';
    }

    std::cout << "after try-catch: " << msg << '\n'; // Here I expect to see an empty msg
                                                     // like this: after try-catch: 

    return 0;
}

I want to move msg to the ctor of std::invalid_argument instead of copying it. I thought that msg should be modified and be left in an unspecified but valid state after the call to std::move. But this happens:

before try-catch: Error!
Error!
after try-catch: Error!

Why is this happening? Is the move ctor of std::string not being called? Or is this some kind of aggressive compiler optimization despite using -O0 option?

CodePudding user response:

Here, the only relevant constructor of std::invalid_argument is:

invalid_argument(const std::string& what_arg);

Const-ref parameter can bind to anything, including an xvalue, which std::move(msg) is. std::move() itself is just a cast, the real work of moving data out of a string could have been made inside a constructor. But you can't modify an xvalue taken by a const-ref. The only option you have is to make a copy, leaving msg unmodified.

Cppreference has the following note, which explains the absence of a constructor taking std::string&&:

Because copying std::invalid_argument is not permitted to throw exceptions, this message is typically stored internally as a separately-allocated reference-counted string. This is also why there is no constructor taking std::string&&: it would have to copy the content anyway.

  • Related