【问题标题】:move ctor of std::string does not work properly?移动 std::string 的 ctor 不能正常工作?
【发布时间】:2021-12-30 18:21:32
【问题描述】:

为什么在调用std::move(msg)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;
}

我想将 msg 移动到 std::invalid_argument 的 ctor 而不是复制它。我认为应该修改msg,并在调用std::move 后保持未指定但有效的状态。但是会发生这种情况:

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

为什么会这样? std::string 的 move ctor 没有被调用吗?还是尽管使用了 -O0 选项,但这是某种激进的编译器优化?

【问题讨论】:

  • std::invalid_argument 有合适的构造函数吗?
  • std::move 只是对右值的强制转换,不保证调用移动构造函数 std::invalid_argument( const std::string&amp; ); 想要一个 const 引用,这里不执行构造函数
  • @MatG 哦,对。我之前没有注意到这一点。解决方案是什么?我是否应该编写一个从std::invalid_argument 派生的异常类,它有一个通过右值引用获取味精的ctor?这还能用吗?
  • 为什么需要移动字符串?请注意,由于小字符串优化,小字符串总是被复制
  • cppreference reads: 因为复制std::invalid_argument 不允许抛出异常,所以该消息通常在内部存储为单独分配的引用计数字符串。这也是为什么没有构造函数采用std::string&amp;&amp;:无论如何它都必须复制内容。

标签: c++ exception move-semantics stdstring


【解决方案1】:

这里,std::invalid_argument 中唯一相关的constructor 是:

invalid_argument(const std::string& what_arg);

Const-ref 参数可以绑定到任何东西,包括 xvaluestd::move(msg) 就是。 std::move() 本身只是一个演员表,将数据移出字符串的真正工作可以在构造函数中完成。但是你不能修改由 const-ref 获取的 xvalue。您唯一的选择是复制一份,保持msg 不变。

Cppreference 有以下note,这解释了没有构造函数采用std::string&amp;&amp;

由于不允许复制std::invalid_argument 引发异常,因此此消息通常在内部存储为单独分配的引用计数字符串。这也是为什么没有构造函数采用std::string&amp;&amp;:无论如何它都必须复制内容。

【讨论】:

  • 我从您的回答中了解到,像 invalid_argument(const std::string&amp; what_arg) 这样的 const lvalue 引用无法获取 lvalue 和 xvalue 参数并移动它们。它只能移动类别纯右值的参数。这是真的吗?
  • @digito_evo 否。为了能够从某个对象移动,它应该可以在函数内部进行修改(这里是在构造函数内部)。如果您通过 const-ref 传递任何值类别的参数,您将永远无法离开它。特别是,如果您通过 const-ref 传递纯右值,则适用相同的规则。
  • 是的,我明白了。这整个话题对我来说有点复杂。
猜你喜欢
  • 2013-05-28
  • 2013-01-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-22
  • 2017-07-07
  • 1970-01-01
相关资源
最近更新 更多