为什么复制省略对形式参数有例外? [英] Why does copy elision make an exception for formal parameters?

查看:32
本文介绍了为什么复制省略对形式参数有例外?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是一个完整的程序:

#include <iostream>
using std::cout;
using std::endl;
using std::move;

int count {0};  // global for monitoring


class Triple {
public:
    Triple() = default;    // C++11 use default constructor despite other constructors being declared
    Triple(Triple&&) = default;
    Triple(const Triple& t) :    // copy constructor
        Triple(t.mX, t.mY, t.mZ) {
        count++;
    }

    Triple(const int x, const int y, const int z) :
        mX{ x }, mY{ y }, mZ{ z } {
    }

    const Triple& operator +=(const Triple& rhs) {
        mX += rhs.mX;
        mY += rhs.mY;
        mZ += rhs.mZ;
        return *this;
    }

    int x() const;
    int y() const;
    int z() const;

private:
    int mX{ 0 };    // c++11 member initialization
    int mY{ 0 };
    int mZ{ 0 };
};


#if 0
inline Triple operator+(const Triple& lhs, const Triple& rhs) {
    Triple left { lhs };
    left += rhs;
    return left;
}
#else
inline Triple operator+(Triple left, const Triple& rhs) {
    left += rhs;
    return left;
}
#endif

int main()
{
    Triple a,b;

    cout << "initial value of count is: " << count << endl;

    auto result { a+b };

    cout << "final value of count is: " << count << endl;
}

有趣的是,复制构造函数有副作用,有两个版本的 operator+ 需要考虑.

Of interest is the fact that the copy constructor has a side effect, and there are two versions of the operator+ to contemplate.

inline Triple operator+(const Triple& lhs, const Triple& rhs) {
    Triple left { lhs };
    left += rhs;
    return left;
}

案例 2

inline Triple operator+(Triple left, const Triple& rhs) {
    left += rhs;
    return left;
}

Visual Studio 2015 给出相同的结果,打印 1 的结果.然而,gcc 4.8.4 为案例 1 提供了 2.

Visual Studio 2015 gives the same result for either, printing a result of 1. However gcc 4.8.4 gives 2 for Case 1.

复制省略 声明哪个不是函数参数",这让我认为 VS 是错误的.对吗?

This summary of copy elision states "which isn't the function parameter" which makes me suppose that VS is wrong. Is that correct?

但是,为什么在这条规则中对形式参数名称进行了特殊处理?为什么它不像任何其他局部变量?

(我不是说优化器根据调用约定以及根据调用者和调用者的单独编译来解决问题,而是说为什么它不被允许.)

(I'm not saying that the optimizer would figure things out depending on calling conventions and in light of separate compilation of caller and call-ee, but merely why it's not allowed.)

如果输出 1 是正确的,它如何符合省略规则?

if outputting 1 is correct, how does that fit with the elision rule?

注意※:我发现此文本是从公开可用的 N3690.

Note ※: I found this text is copied from §12.8 paragraph 31 in the publicly available N3690.

推荐答案

如果复制省略被禁用,两种情况都由 1 个复制和 3 个移动组成.(您的代码的任何 2 输出都表明存在编译器错误).

If copy elision is disabled, both cases consist of 1 copy followed by 3 moves. (Any output of 2 for your code would indicate a compiler bug).

副本是:

  • 初始化left

而动作是:

  • left
  • 初始化返回值
  • 返回值
  • 初始化a+b表示的临时对象
  • a+b
  • 初始化result

用输出消息替换 count 会更有启发性,说 "in copy constructor""in move constructor" .目前您根本没有跟踪移动.

It would be more illuminating to replace count with an output message saying "in copy constructor" and "in move constructor" . Currently you are not tracking moves at all.

在传递引​​用的情况下,可以省略所有 3 个移动.在按值传递的情况下,可以省略 2 个移动.不能省略的移动是从left返回值的移动.

In the pass-by-reference case , all 3 moves can be elided. In the pass-by-value case, 2 of the moves can be elided. The move which cannot be elided is the move from left to the return value.

我不知道为什么不能省略这一举动的理由.如果 A() 一直到 都是可省略的,那么编译器可能很难做类似 A a = foo( A() ); 的事情>a.

I don't know the rationale for why this move can't be elided. Maybe it'd be difficult for a compiler to do something like A a = foo( A() ); if A() were elidable all the way up to a.

这篇关于为什么复制省略对形式参数有例外?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆