为什么在C ++容器中存储引用(而不是指针)无法工作?

45

我在程序中使用了STL set。

set<string> myStrings;
为了提高代码的效率,我将其改为仅保存指针(我不需要存储实际的字符串副本)。
set<string*> myStrings;

我读过,如果可能的话,用引用替换指针是一个好的实践。(当然,仅在指针的实际功能不需要时。)

set<string&> myStrings;

虽然后一种方法更简洁,但会产生很多编译错误。 为什么不能将引用作为容器元素使用?


2
考虑使用智能指针,如shared_ptr(或者,如果您的实现支持右值引用,则使用unique_ptr,但从您的问题描述来看,似乎不是您要寻找的)。 - James McNellis
2
顺便说一句:依我之见,"在可能的情况下,用引用替换指针"通常是浪费时间的,因为它们的限制性更大,而且最终你肯定会意识到需要将它们全部交换回来,比如你需要将它们设为NULL或重新赋值等。真正需要使用引用的唯一原因就是使某些运算符重载在语法上看起来更加优雅。 - Oliver Charlesworth
2
你认为存储指向字符串的指针而不是字符串会使它更有效率,这是什么原因呢?现代字符串具有非常高效的复制机制,因此你获得的收益可能不会很显著,并且它增加的代码复杂性不值得这种收益。 - Martin York
这不就是按值传递或按引用传递参数给函数吗? - ruslik
4
使用C++11,你可以使用std::reference_wrapper来存储一个对象的引用。 - Willem D'Haeseleer
3个回答

59

容器存储对象。引用不是对象。

C++11规范明确指出(§23.2.1[container.requirements.general]/1):

容器是存储其他对象的对象。


18
这不是一个好的答案。C++中的容器可以包含任何东西,而不仅仅是对象。例如,你可以有set<int>、set<int*>等。引用在物理层面上是一个指针,但是因为编译器需要实例化接受你元素类型引用的函数,并且因为C++无法处理双重引用,所以set<int&>是不可能的。 - mojuba
15
在C++中,当我们说对象时,我们指的是任何数据类型的实例,包括内置类型。 - Benjamin Lindley
15
@mojuba: intint*都是对象(在C++中,“对象是存储区域”(C++03 1.8/1))。引用永远不是对象。引用C++标准的话,“容器是存储其他对象的对象”(23.1/1)。 - James McNellis
4
@mojuba -- 你在编译器中遇到的错误取决于编译器提供的容器具体实现。标准并未规定任何特定的实现方式,它采用了非常黑盒的方法。例如,它会说“容器的值类型必须既能被复制构造,又能被赋值”,而不用担心复制和赋值是如何实现的。我将为您进行翻译。 - Benjamin Lindley
3
@mojuba: 不,那不是真的。编译器将在特定 STL 实现尝试使用赋值操作的第一个地方失败。这可能会在模板实现代码内部深入 20 个函数调用,或者 2 个函数调用深度内发生,但仍符合标准。哦,对了,引用是不可赋值的。 - Billy ONeal
显示剩余8条评论

23

虽然不直接与“为什么”有关,但为了回答意味着要这样做的暗示,我想提到C++11标准库具有std::reference_wrapper,可以实现这一点。它可以隐式转换为引用并存储在标准容器中。


1
链接到您的答案:http://en.cppreference.com/w/cpp/utility/functional/reference_wrapper - leon22

6
作为容器,存储对象而不是引用。如果你使用的是c++ 11,你可以使用std::reference_wrapper将事物包装成可分配的对象。
std::reference_wrapper是一个类模板,它将引用包装在可复制、可分配的对象中。它经常被用作一种机制来在标准容器(如std::vector)中存储引用,这些容器通常不能持有引用。
参考链接:http://en.cppreference.com/w/cpp/utility/functional/reference_wrapper

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接