为什么下面的代码不调用 std::string 的移动构造函数?

Why does the following code not invoke std::string's move constructor?

本文关键字:string 移动 std 构造函数 调用 代码 为什么      更新时间:2023-10-16

以下代码在VS2013上编译,从不调用std::string的移动构造函数(通过设置断点进行检查,而是调用const-ref-copy构造函数。

#include <iostream>
#include <string>
#include <stdlib.h> /* srand, rand */
#include <time.h> /* time */
struct foo
{
    foo(std::string& str1, std::string& str2) : _str1(str1), _str2(str2) {}
    ~foo() { std::cout << "Either "" << _str1 << "" or "" << _str2 << "" was returned." << std::endl; }
    std::string& _str1;
    std::string& _str2;
};
std::string foobar()
{
    std::string str1("Hello, World!");
    std::string str2("Goodbye, cruel World.");
    foo f(str1, str2);
    srand(time(NULL));
    return (rand() % 2) ? str1 : str2;
}
int main()
{
    std::cout << """ << foobar() << "" was actually returned." << std::endl;
    return EXIT_SUCCESS;
}

我希望foobar()中的return语句能够调用move构造函数,因为我正在返回一个local(rand()是为了防止NRVO),就像对诸如返回局部变量的std::move之类的问题的回答一样

这是因为我试图在这里为我的另一个问题添加另一个例子:https://softwareengineering.stackexchange.com/questions/258238/move-semantics-in-c-move-return-of-local-variables

C++11有一个特殊的情况,当它是一个局部变量并用作函数的返回表达式时,它允许复制/移动省略:

C++11 12.8/31"复制和移动类对象":

在具有类返回类型的函数的return语句中,当表达式是非易失性自动对象的名称(除函数或catch子句参数)具有相同cv不合格类型作为函数返回类型,复制/移动操作可以通过将自动对象直接构造到函数的返回值

但是,由于返回语句不仅仅是"非易失性自动对象的名称",因此不满足复制省略的这种情况。

后来,标准提到

C++11 12.8/32"复制和移动类对象":

当满足或将满足省略复制操作的标准时除了源对象是函数参数这一事实之外,并且要复制的对象由左值重载指定首先执行为副本选择构造函数的解析就好像对象是由右值指定的一样。如果过载解决方案失败,或者如果所选的第一个参数的类型构造函数不是对对象类型的右值引用(可能cv合格),考虑到对象作为左值。[注:此两阶段过载解决方案必须无论是否会发生复制省略,都将执行。它如果不执行省略,则确定要调用的构造函数,并且所选构造函数必须是可访问的,即使调用是消隐。——尾注]

这样,即使返回指定了左值,也可以使用移动操作。然而,这种特殊情况仅适用于第一句的条件,而在示例return语句的情况下则不满足这些条件。

你可以强制发布:

return (rand() % 2) ? std::move(str1) : std::move(str2);