C++ 使用if语句移动构造函数,但使用三元运算符复制构造函数

C++ 使用if语句移动构造函数,但使用三元运算符复制构造函数,c++,c++11,move-semantics,C++,C++11,Move Semantics,上下文:我在做实验,以了解gcc何时执行,如果不执行,它何时使用移动语义。我的gcc版本是g++(gcc)4.8.5 20150623(Red Hat 4.8.5-4) 问:我有一个函数,它按值返回Foo。编译器无法执行RVO,因为有两个可能的命名返回值。当我使用三元运算符选择返回哪个Foo时,我需要显式调用std::move,以避免复制。使用if语句时,我不需要std::move。为什么会有差异 代码: 在某些情况下有一种隐含的移动: §12.8.32 当满足省略复制/移动操作的条件时,但是

上下文:我在做实验,以了解gcc何时执行,如果不执行,它何时使用移动语义。我的gcc版本是
g++(gcc)4.8.5 20150623(Red Hat 4.8.5-4)

问:我有一个函数,它按值返回
Foo
。编译器无法执行RVO,因为有两个可能的命名返回值。当我使用三元运算符选择返回哪个
Foo
时,我需要显式调用
std::move
,以避免复制。使用if语句时,我不需要
std::move
。为什么会有差异

代码:


在某些情况下有一种隐含的移动:

§12.8.32

当满足省略复制/移动操作的条件时,但是 不适用于异常声明,并且要复制的对象是 由左值指定,或者当返回语句中的表达式 是一个id表达式(可能带括号),它用 正文中声明的自动存储持续时间最内层封闭函数的参数声明子句或 lambda表达式,用于选择构造函数的重载解析 首先执行复制,就像对象由 右值。如果第一次重载解析失败或未执行, 或者如果所选构造函数的第一个参数的类型为 不是对对象类型的右值引用(可能是cv限定), 再次执行重载解析,将对象视为 左值


我的粗体字

有特殊的措辞,用于
返回本地名称使
移动
隐式存在。@sp2danny Thx。根据该标准,对于三元运算符,是否允许更智能的编译器隐式地
移动
。或者标准是这样说的如果return语句的格式为
return name of local
,则必须隐式移动,否则不能隐式移动`?我想我可以自己看看。谢谢!我查看了标准,但找不到适当的条款,我一点也不习惯。因此,这似乎可以解释为什么if版本能够正常工作。在三元运算符的情况下,我假设表达式
哪个?foo1:foo2
首先被求值(这会产生一个副本,返回一个未命名的临时文件),然后编译器通过执行RVO来删除从这个临时文件到
fooTernary
的副本。听起来对吗?@boris no,
在两种相同类型的值上不会创建副本。@yack Thnks,你说得对,如果我执行
std::move(哪个?foo1:foo2)
,也不会发生复制!:)
#include <iostream>

using namespace std;

struct Foo {
    std::string s;
    Foo()                                        { cout << "Foo()\n"; }
    ~Foo()                                       { cout << "~Foo()\n"; }
    Foo(const Foo& other)     : s(other.s)       { cout << "Foo(const Foo&)\n"; }
    Foo(Foo&& other) noexcept : s(move(other.s)) { cout << "Foo(Foo&&)\n"; }
};

Foo makeFooIf(bool which) {
    Foo foo1; foo1.s = "Hello, World1!";
    Foo foo2; foo2.s = "Hello, World2!";
    if (which) return foo1;
    else       return foo2;
}

Foo makeFooTernary(bool which) {
    Foo foo1; foo1.s = "Hello, World1!";
    Foo foo2; foo2.s = "Hello, World2!";
    return which ? foo1 : foo2;
}

Foo makeFooTernaryMove(bool which) {
    Foo foo1; foo1.s = "Hello, World1!";
    Foo foo2; foo2.s = "Hello, World2!";
    return which ? move(foo1) : move(foo2);
}

int main()
{
    cout << "----- makeFooIf -----\n";
    Foo fooIf = makeFooIf(true);
    cout << fooIf.s << endl;

    cout << "\n----- makeFooTernary -----\n";
    Foo fooTernary = makeFooTernary(true);
    cout << fooTernary.s << endl;

    cout << "\n----- makeFooTernaryMove -----\n";
    Foo fooTernaryMove = makeFooTernaryMove(true);
    cout << fooTernaryMove.s << endl;

    cout << "\n----- Cleanup -----\n";
    return 0;
}
----- makeFooIf -----
Foo()
Foo()
Foo(Foo&&)
~Foo()
~Foo()
Hello, World1!

----- makeFooTernary -----
Foo()
Foo()
Foo(const Foo&)
~Foo()
~Foo()
Hello, World1!

----- makeFooTernaryMove -----
Foo()
Foo()
Foo(Foo&&)
~Foo()
~Foo()
Hello, World1!

----- Cleanup -----
~Foo()
~Foo()
~Foo()