考虑以下代码:
int main()
{
std::vector<std::string> v;
v.push_back("hello");
v.push_back("stack");
std::string &s = v[0];
v.push_back("overflow");
std::cout << s << std::endl;
return 0;
}
运行后(使用g++ (Ubuntu 4.8.4-2ubuntu1~14.04.1) 4.8.4
),只打印一个空行,不打印hello
。如果我注释掉v.push_back("stack");
,则会出现细分错误。
现在我明白为什么会这样。向向量添加更多元素会触发引擎下的增长操作,之后我的旧引用变为无效。这不是我的问题。
我的问题是这种行为 - 在获取引用/指针后修改向量或其他STL容器 - 是否被定义为C ++标准中的未定义行为?如果是的话,在哪里?如果没有那么标准对这种情况说了什么?
答案 0 :(得分:3)
C ++ 14 [vector.capacity] / 6:
重新分配使引用序列中元素的所有引用,指针和迭代器无效。
[vector.modifiers] / 6涵盖了push_back
可能导致重新分配的问题,只有在迭代器没有重新分配时才会失效。
我实际上找不到任何文本来定义引用无效的含义,但很明显暗示在无效之后使用引用的值将是未定义的行为。
答案 1 :(得分:2)
仅仅因为您通过某种方式获取了迭代器,引用或指针,因此不会禁止修改容器。 可能无效的是迭代器,引用或指针本身。
§23.3.6.6[vector.modifiers] (包括push_back
成员系列)
- 备注:如果新大小大于旧容量,则会导致重新分配。如果没有重新分配,则之前的所有迭代器和引用 插入点仍然有效。如果抛出异常而不是 通过复制构造函数,移动构造函数,赋值运算符或 移动
醇>T
的赋值运算符或任何InputIterator操作 没有影响。如果插入单个时抛出异常 最后的元素和T
是CopyInsertable或is_nothrow_move_constructible<T>::value
是真的,没有效果。 否则,如果a的移动构造函数抛出异常 非CopyInsertableT
,效果未指定。
如果没有发生调整大小,则只有插入点之后的引用,指针和迭代器(包括结束迭代器)无效。很好,但如果重新分配发生会发生什么?有趣的是,我们发现:
§23.3.6.3[vector.capacity]
但是,我并不完全相信这完全回答了你的问题。如果你想知道占用矢量的先前内存发生了什么,那就是标准库,但它不再包含可行的内容。容器不再拥有内存(据你所知),你也不知道。
- 备注:重新分配使所有引用,指针和 迭代器引用序列中的元素。没有重新分配 应在呼叫后发生的插入过程中发生 reserve()直到插入的大小为止 vector大于capacity()的值。
醇>