任何编译器真的会删除这些副本吗?
Will any compiler actually ever elide these copies?
给出
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))
中,编译器可以通过在 box
中构建它们来避免完全复制 Range
对象。
真的有编译器这样做吗?
我自己的尝试没有成功。
编译器可以——而且通常会——将副本从临时文件中删除到参数中。编译器不能 删除从参数到成员的副本。虽然在某些情况下在技术上可以删除这些副本,但未获得相关许可。该标准的部分是 12.8 [class.copy] 第 31 段,它阐明了可以省略副本的 4 种情况(确切的规则有点不平凡):
- 当使用它的名称返回命名的函数局部变量时。
- 在
throw
表达式中使用命名函数局部变量时。
- 复制临时对象时。
- 按值捕获异常时。
显然,将命名参数作为参数传递给成员变量的构造是 none 这些情况。
复制省略规则的基本背景是,在某些情况下,函数声明足以确定何时使用对象。如果在构造时间清楚可以构造对象的位置,则可以将其省略。构造函数的调用者不能仅根据构造函数的声明来确定将在何处使用对象。
那个人就是我。所以让我表明立场。
我从来没有说过在 Box box(Range(0.0,1.0),Range(0.0,2.0))
中,编译器可以避免复制 Range 对象 完全 通过在框内构造它们来开始。我说的是:
是的,特别是这种复制省略上下文属于 12.8/p31.3 复制和移动 class 对象 [class.copy 中指定的复制省略标准] 标准:
(31.3) -- when a temporary class object that has not been bound to a reference
(12.2) would be copied/moved to a class object with the same type
(ignoring cv-qualification), the copy/move operation can be omitted by
constructing the temporary object directly into the target of the
omitted copy/move.
是的,它可以,部分用于在构造函数中传递的临时对象(可以按照上面提到的标准省略)。我从来没有说过参数可以一直省略到 Box
构造函数的初始化列表。
毕竟,这种情况不符合任何可以根据标准应用复制省略的标准。
我也说过,即使某个上下文被限定为可以应用复制省略的上下文,编译器也没有义务遵循。如果您依赖于该效果,那么您的程序不被认为是可移植的。
给出
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))
中,编译器可以通过在 box
中构建它们来避免完全复制 Range
对象。
真的有编译器这样做吗?
我自己的尝试没有成功。
编译器可以——而且通常会——将副本从临时文件中删除到参数中。编译器不能 删除从参数到成员的副本。虽然在某些情况下在技术上可以删除这些副本,但未获得相关许可。该标准的部分是 12.8 [class.copy] 第 31 段,它阐明了可以省略副本的 4 种情况(确切的规则有点不平凡):
- 当使用它的名称返回命名的函数局部变量时。
- 在
throw
表达式中使用命名函数局部变量时。 - 复制临时对象时。
- 按值捕获异常时。
显然,将命名参数作为参数传递给成员变量的构造是 none 这些情况。
复制省略规则的基本背景是,在某些情况下,函数声明足以确定何时使用对象。如果在构造时间清楚可以构造对象的位置,则可以将其省略。构造函数的调用者不能仅根据构造函数的声明来确定将在何处使用对象。
那个人就是我。所以让我表明立场。
我从来没有说过在 Box box(Range(0.0,1.0),Range(0.0,2.0))
中,编译器可以避免复制 Range 对象 完全 通过在框内构造它们来开始。我说的是:
是的,特别是这种复制省略上下文属于 12.8/p31.3 复制和移动 class 对象 [class.copy 中指定的复制省略标准] 标准:
(31.3) -- when a temporary class object that has not been bound to a reference (12.2) would be copied/moved to a class object with the same type (ignoring cv-qualification), the copy/move operation can be omitted by constructing the temporary object directly into the target of the omitted copy/move.
是的,它可以,部分用于在构造函数中传递的临时对象(可以按照上面提到的标准省略)。我从来没有说过参数可以一直省略到 Box
构造函数的初始化列表。
毕竟,这种情况不符合任何可以根据标准应用复制省略的标准。
我也说过,即使某个上下文被限定为可以应用复制省略的上下文,编译器也没有义务遵循。如果您依赖于该效果,那么您的程序不被认为是可移植的。