【发布时间】:2018-06-16 00:24:33
【问题描述】:
考虑以下代码:
std::vector<int> Foo() {
std::vector<int> v = Bar();
return v;
}
return v 是 O(1),因为 NRVO 将省略副本,构造 v directly in the storage where the function's return value would otherwise be moved or copied to。现在考虑功能类似的代码:
void Foo(std::vector<int> * to_be_filled) {
std::vector<int> v = Bar();
*to_be_filled = v;
}
可以在这里提出类似的论点,因为*to_be_filled = v 可以被编译为 O(1) 移动分配,因为它是一个超出范围的局部变量(编译器应该很容易验证v 在这种情况下没有外部引用,因此在最后一次使用时将其提升为右值)。是这样吗?有什么微妙的原因吗?
此外,感觉这种模式可以扩展到左值超出范围的任何上下文:
void Foo(std::vector<int> * to_be_filled) {
if (Baz()) {
std::vector<int> v = Bar();
*to_be_filled = v;
}
...
}
期望编译器找到诸如*to_be_filled = v 之类的模式,然后自动优化它们以假定右值语义是否有用/合理?
编辑:
g++ 7.3.0 不在 -O3 模式下执行任何此类优化。
【问题讨论】:
-
我很确定标准不允许这种优化。但是,您可能会提交将其添加到标准中的提案(这意味着当
v出现在作业右侧的唯一内容时,v超出范围,而v不在't 在左侧),这样v就会被移动,或者甚至可以省略副本 -
你为什么不尝试使用用户定义的类来打印构造函数和析构函数中的消息,看看使用了什么。
-
@Justin:我一直在考虑提交一个接近此的提案,但想弄清楚我们可以制作这种模式的通用性,为它编写优化的难度/成本有多大, 与该模式在现实世界中的常见程度(即:我给出的示例很容易检测到,但可能不太常见)。
-
@Barmar:好点。我编辑了问题以包含 g++ 的结果。不出所料,这种优化似乎没有实现,至少在 -O3 中是这样。
-
@AndréHarder 查看std-proposals google 组。这就是我要从提案开始的地方(稍微充实我的想法,在那里提出)。请注意,这实际上是该语言的一个相当困难的角落。在每种情况下都有很多陷阱可以防止这种情况发生,但您可以针对某些特定情况提出建议。
标签: c++ compiler-optimization rvalue nrvo