c++ - const ref lvalue to non-const func return value 是否专门减少拷贝?

标签 c++ reference constants

我遇到了一个 C++ 习惯,我试图研究它以了解它的影响并验证它的用法。但我似乎找不到确切的答案。

std::vector< Thing > getThings();

void do() {
    const std::vector< Thing > &things = getThings();   
}

这里我们有一些返回非const& 值的函数。我看到的习惯是在分配函数的返回值时使用 const& 左值。提出这个习惯的原因是它减少了拷贝。

现在我一直在研究 RVO(返回值优化)、复制省略和 C++11 移动语义。我意识到给定的编译器可以选择阻止通过 RVO 进行复制,不管这里是否使用了 const&。但是,在防止复制方面,const& 左值的使用对非 const& 返回值有任何影响吗?我特别询问 C++11 之前的编译器,之前 移动语义。

我的假设是编译器要么实现 RVO,要么不实现,并且说左值应该是 const& 并不暗示或强制出现无拷贝情况。

编辑

我特别询问这里使用const& 是否会减少拷贝,而不是临时对象的生命周期,如"the most important const" 中所述。

进一步澄清问题

这是:

const std::vector< Thing > &things = getThings();

与此不同的是:

std::vector< Thing > things = getThings();

在减少拷贝方面?或者它对编译器是否可以减少拷贝没有任何影响,例如通过 RVO?

最佳答案

从语义上讲,编译器需要一个可访问的复制构造函数,在调用点,即使稍后,编译器省略了对复制构造函数的调用——优化是在编译的后期完成的语义分析阶段之后的阶段。

阅读您的评论后,我想我更好地理解了您的问题。现在让我详细回答一下。

假设函数有这个返回语句:

return items;

从语义上讲,编译器需要这里有一个可访问的复制构造函数(或移动构造函数),它可以被省略。然而,只是为了争论,假设它在这里制作了一个拷贝,并且拷贝存储在 __temp_items 中,我将其表示为:

__temp_items <= return items; //first copy: 

现在在调用处,假设你还没有使用const &,所以就变成了这样:

std::vector<Thing> things = __temp_items;  //second copy

现在如您所见,有两个拷贝。允许编译器省略它们。

然而,你的实际代码使用了const &,所以它变成了这样:

const std::vector<Thing> & things = __temp_items;  //no copy anymore.

现在,语义上只有一个拷贝,编译器仍然可以将其删除。至于第二个拷贝,我不会说 const& “阻止” 它是因为编译器已经优化了它,而是语言一开始就不允许它。


但有趣的是,无论编译器在返回时复制了多少次,或者省略了其中的一部分(或全部),返回值都是一个临时。如果是这样,那么如何绑定(bind)到临时工作?如果这也是您的问题(现在我知道这不是您的问题,但请保持这种方式,这样我就不必删除我的这部分答案),那么是的,它可以工作并且可以保证通过语言。

如文章 the most imporant const 中所述非常详细地说,如果 const 引用绑定(bind)到临时对象,则临时对象的生命周期会延长到引用的范围内,并且它与对象的类型无关.

在C++11中,还有另一种延长临时对象生命周期的方法,即右值引用:

std::vector<Thing> && things = getThings();    

它具有相同的效果,但优点(或缺点 — 取决于上下文)是您还可以修改内容。

我个人更喜欢这样写:

auto && things = getThings();   

但是那不一定是一个右值引用——如果你改变函数的返回类型,返回一个引用,那么 things 结果绑定(bind)到左值引用。如果您想对此进行讨论,那将是一个完全不同的话题。

关于c++ - const ref lvalue to non-const func return value 是否专门减少拷贝?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38909228/

相关文章:

c++ - 反向迭代器算法

c++ - C++ 库的 Python 包装器

c++ - 如何帮助编译器消除循环和数组?

c++ - 使用静态函数初始化 static const int

C# 字符串常量与静态属性

c++ - 不是最重要的 const.. 但这是什么?

c++ - 从 MinGW 链接到 OpenCV 的问题

vb.net - Visual Studio 找不到引用

Perl:我可以使用变量来命名数组吗?

Java 引用不正确