6

给定

struct Range{
    Range(double from, double to) : from(from), to(to) {}
    double from;
    double to;
    // if it matters to the compiler, we can add more fields here to make copying expensive
};

struct Box{
    Box(Range x, Range y) : x(x), y(y) {}
    Range x;
    Range y;
};

有人说,在 中Box box(Range(0.0,1.0),Range(0.0,2.0)),编译器可以Range通过在内部构造对象来完全避免复制对象box

任何编译器实际上都这样做吗?

我自己的尝试没有成功。

4

2 回答 2

8

编译器可以——而且通常会——将副本从临时文件删除到参数。编译器不能从参数中删除副本到成员。虽然在某些情况下可能在技术上可以省略这些副本,但未给予相关许可。标准的部分是 12.8 [class.copy] 第 31 段,它阐明了可以省略副本的 4 种情况(确切的规则有点不重要):

  1. 返回使用名称的命名函数局部变量时。
  2. throw表达式中使用命名的函数局部变量时。
  3. 复制临时对象时。
  4. 按值捕获异常时。

显然,将命名参数作为参数传递给成员变量的构造不是这些情况。

复制省略规则的基本背景是,在某些情况下,函数的声明足以确定何时使用对象。如果在构建时明确可以构建对象的位置,则可以省略它。构造函数的调用者不能仅根据构造函数的声明来确定对象将在哪里使用。

于 2015-11-23T14:50:52.837 回答
0

那个人就是我。所以让我澄清一下我的立场。

我从来没有说过,编译器可以通过在框内构造它们来完全Box box(Range(0.0,1.0),Range(0.0,2.0))避免复制 Range 对象。我说的是:

是的,它可以,特别是这种复制省略上下文属于标准的12.8/p31.3 复制和移动类对象 [class.copy]中指定的复制省略标准:

(31.3) -- 当尚未绑定到引用 (12.2) 的临时类对象将被复制/移动到具有相同类型的类对象(忽略 cv 限定)时,可以通过以下方式省略复制/移动操作将临时对象直接构造到省略的复制/移动的目标中。

Yes it can , 部分用于构造函数中传递的临时对象(如上所述,可以根据标准省略)。我从来没有说过参数可以一直省略到Box构造函数的初始化列表。

毕竟,这种情况不符合任何可以根据标准应用复制省略的标准。

我还说过,即使某个上下文被限定为可以应用复制省略的上下文,编译器也没有义务遵循。如果您依赖这种效果,那么您的程序不被认为是可移植的。

于 2015-11-23T19:53:31.987 回答