C++ 返回对向量中值的引用
Posted
技术标签:
【中文标题】C++ 返回对向量中值的引用【英文标题】:C++ returing a reference to a value in vector 【发布时间】:2018-10-24 00:19:16 【问题描述】:给定以下程序:
#include <iostream>
#include <utility>
#include <vector>
#include <unordered_map>
#ifdef WITHPAIR
auto get_state()
std::pair<std::vector<unsigned>, std::unordered_map<unsigned, unsigned&>> st;
auto& v = st.first;
auto& index = st.second;
v.assign(1u,2u,3u,4u);
index.insert(0u, v[0]);
index.insert(1u, v[1]);
index.insert(2u, v[2]);
index.insert(3u, v[3]);
return st;
#else
std::pair<std::vector<unsigned>, std::unordered_map<unsigned, unsigned&>> get_state()
std::vector v1u,2u,3u,4u;
std::unordered_map<unsigned, unsigned&> index
0u, v[0],
1u, v[1],
2u, v[2],
3u, v[3]
;
return v, index;
#endif
auto main() -> int
auto [v, index] = get_state();
// auto [v, index] = std::move(get_state());
std::cout << v[0] << " " << index.at(0) << std::endl;
v[0] = 5;
std::cout << v[0] << " " << index.at(0) << std::endl;
std::cout << v[1] << " " << index.at(1) << std::endl;
v[2] = 17;
std::cout << v[2] << " " << index.at(2) << std::endl;
std::cout << v[3] << " " << index.at(3) << std::endl;
return 0;
http://coliru.stacked-crooked.com/a/f9e528074ae78c03
不使用-DWITHPAIR
进行编译以查看第二个函数的行为
函数get_state
有两个版本。
只有第一个函数似乎具有正确的行为,并且在从函数返回时实际上使该数据可用(从链接的程序中可以看到);第二个函数的行为不是这样,并且 unordered_map 中的值与向量中的值不同。
我的问题是两个:
第一个函数的行为是否正确?是否是未定义的行为? 为什么第二个会改变向量?【问题讨论】:
因为第二个有UB,第一个没有 @Slava 请将此作为答案。第二个的UB是多少? 第二个v
没有被移动,而是被复制,所以所有的引用都失效了。如果您明确移动v
,它应该会修复它。
因为RVO导致第一个没有副本
是的,它被复制到,你也应该移动它,但是为了效率和一致性,但不移动 v
会由于地图中的无效引用而带来 UB。
【参考方案1】:
由于NRVO,您的第一个功能似乎可以工作:
在return语句中,当操作数是具有自动存储持续时间的非易失性对象的名称时,该对象不是函数参数或catch子句参数,并且属于同一类类型(忽略cv-资格)作为函数返回类型。这种复制省略的变体被称为 NRVO,“命名返回值优化”。
如果发生这种情况,则没有执行复制,并且地图中的引用仍然有效,但由于 NRVO 是一种优化,因此不能保证您只是幸运地工作。
在第二个函数中,您创建std::pair<std::vector<unsigned>, std::unordered_map<unsigned, unsigned&>>
类型的临时对象,并使用左值v
和index
对其进行初始化,因此为它们调用了复制构造函数,并且所有引用在原始v
时都无效被摧毁。修复可能是显式调用std::move
:
return std::move(v), index;
并且作为标准保证引用保持有效并指向新向量中的元素,因此应该不再有 UB。 index
也应该移动以提高效率和一致性,但我留下了它,因为它与问题无关。
这是一种非常危险的编程方式,我会考虑不同的数据类型(可能是向量中的索引而不是引用)。
【讨论】:
最后感谢您的建议。在尝试复制这对配对后,我很快意识到了这一点 @smac89 np,在容器中引用通常不是一个好主意,但对矢量元素的引用更糟糕。 这是 NRVO,不能保证。以上是关于C++ 返回对向量中值的引用的主要内容,如果未能解决你的问题,请参考以下文章