考虑这些免费的独立功能:
std::vector<int>& f(); //reference
std::vector<int> g(); //value
/*const*/ std::vector<int>& f1 = f(); //reference
std::vector<int> f2 = f(); //value
/*const*/ std::vector<int>& g1 = g(); //reference
std::vector<int> g2 = g(); //value
之间有什么区别:
f()和g()。这是一个简单的问题,但我仍然希望听到一些关于它们的详细评论,因为它可能有助于理解下一个问题的答案。
f1和f2。它们是否与f()中的原始对象相同,或者f2将是原始的副本?取消注释const
会有什么不同吗?
g1和g2。它们是否与g()中的原始对象相同,或者g2是原始的副本?取消注释const
会有什么不同吗?
如果f()
和g()
是成员函数,并且每个都返回成员数据,而不是某些局部变量,该怎么办?它会对上述问题的答案产生任何影响吗?
请尝试在回答中包含所有陷阱和重点,并且不要考虑RVO或编译器的任何其他优化。我想知道C ++是什么,而不是编译器做什么。如果你谈论优化,请明确提及它,这样我就不会将语言特性与编译器功能混合在一起。
答案 0 :(得分:8)
f()
返回对象的引用;从它返回不会复制任何对象。 g()
至少在概念上返回一个对象的副本。
std::vector<int>& f1 = f(); //reference
f1
指的是f()
返回引用的对象。没有制作副本。引用的const限定在这里没有区别(就复制而言;显然它会影响对象可以做什么)。
std::vector<int> f2 = f(); //value
f2
是f()
返回引用的对象的副本。
std::vector<int>& g1 = g(); //reference
这是无效的。非const引用不能绑定到临时对象。
如果引用是const限定的,那么这一行实际上与下一行相同:g()
返回的对象的副本,引用绑定到该副本,并且该副本是给定引用的生命周期(当引用被“销毁”时它被销毁)。
std::vector<int> g2 = g(); //value
g2
是g()
返回的对象的副本。是否制作副本(以及可以制作多少副本)取决于编译器优化。
如果
f()
和g()
是成员函数,并且每个都返回成员数据,而不是某些局部变量,该怎么办?
如果f()
返回对局部变量的引用,则程序不正确并且如果您尝试使用该引用则会产生未定义的行为,因为当函数返回时,引用的对象不再存在。
如果f()
返回对成员变量,动态分配的对象或具有静态或线程本地存储持续时间的对象的引用,则该引用对该对象的生命周期(或对象的另一个对象)有效。在内存中与返回引用的对象相同的位置构造的相同类型,尽管其实用性仅限于少数情况。)
g()
返回的内容并不重要,因为始终会制作副本(至少在概念上)。