是否所有STL容器都通过引用返回其元素?

时间:2011-08-18 14:52:29

标签: c++ stl

这些天我正在学习STL,我想知道STL容器是否通过引用返回

e.g:

vector.first();
map[key];
*vector.begin();
Or any possible return that ends with element (or value type) of container

e.g:

std::vector<int> elements;
elements.push_back(20);
elements[0]=60; // this will also change the value
elements.front() = 23; // even the functions also behave same way like subscript operator

这是所有容器的情况吗?还是有一些要考虑的问题我没有表现出来?

4 个答案:

答案 0 :(得分:13)

无法以安全的方式返回添加的元素或容器成员函数中的容器。 STL容器主要提供“强保证”。返回操纵元素或容器将使得不可能提供强有力的保证(它只提供“基本保证”)。这些术语的解释在boost的网站 Exception-Safety in Generic Components 上提供。请参阅下面的Boost's website

  • 基本保证:保留组件的不变量,不泄漏任何资源。
  • 强保证:操作已成功完成或抛出异常,使程序状态与操作开始前完全一致。
  • no-throw guarantee :操作不会抛出异常。

回到主题:根据这个previous SO answer,背后的原因是,返回一些东西可能会调用一个拷贝构造函数,这可能会引发一个异常。但是这个功能已经退出,所以它成功地完成了它的主要任务,但仍然抛出异常,这违反了强有力的保证。您可能会想:“那么让我们通过引用返回!”,虽然这听起来像是一个很好的解决方案,但它也不是非常安全。请考虑以下示例:

MyClass bar = myvector.push_back(functionReturningMyClass()); // imagine push_back returns MyClass&

但是,如果复制赋值运算符抛出,我们不知道push_back是否成功,从而间接违反了强保证。即使这不是直接违规。当然使用MyClass& bar = //...可以解决这个问题,但是容器可能会进入不确定的状态会非常不方便,因为有人忘记了&amp;。

std::stack::pop()未返回弹出值的事实背后有一个非常相似的推理。相反,top()以安全的方式返回最顶层的值。在调用top之后,即使复制构造函数或复制赋值构造函数抛出,您仍然知道堆栈没有改变。

答案 1 :(得分:2)

容器的所有类型(序列,关联)旨在提供一致的接口(如果可能)。它使学习它们相对容易,并且使用它们更容易(只要你已经正确地学习它们了!;))。

因此,例如,所有容器的operator[]将返回对索引实体的引用(在关联容器的情况下,将首先创建它)。对于序列容器,这提出了一个关于边界检查的有趣观点 - 但这是一个不同的故事。同样,如果您采取任何其他常见操作(insert等)将具有类似的界面。您最喜欢的参考文献通常会提供您需要的所有信息。

答案 2 :(得分:2)

是的,stl容器的重载[]运算符返回一个引用。因此,在上面的示例中,melements中的值将被更改。

来自http://www.cplusplus.com/reference/stl/vector/operator%5B%5D/

vector的定义或运算符[]是:

reference operator[] ( size_type n );
const_reference operator[] ( size_type n ) const;

其中'成员类型referenceconst_reference是向量容器元素的引用类型(在大多数存储分配模型中通常分别定义为T&const T& )'

编辑:请注意,并非所有stl容器都有重载的[]运算符。那些不是:listmultimapmultisetpriority_queuequeuesetstack

答案 3 :(得分:1)

除了对bool的引用之外,允许

std::vector<bool>返回其他内容(假设您的意思是标准库,而不是SGI STL)。但它通常也被认为是一个不值得被称为容器的错误。