C++ Don';例如,我不理解迭代器、引用和指针无效

C++ Don';例如,我不理解迭代器、引用和指针无效,c++,C++,我读过很多关于引用、指针和迭代器失效的帖子。例如,我已经读到插入使对deque元素的所有引用无效,那么为什么在下面的代码中我没有错误 #include <deque> int main() { std::deque<int> v1 = { 1, 3, 4, 5, 7, 8, 9, 1, 3, 4 }; int& a = v1[6]; std::deque<int>::iterator it = v1.insert(v1.beg

我读过很多关于引用、指针和迭代器失效的帖子。例如,我已经读到插入使对deque元素的所有引用无效,那么为什么在下面的代码中我没有错误

#include <deque>

int main()
{
    std::deque<int> v1 = { 1, 3, 4, 5, 7, 8, 9, 1, 3, 4 };
    int& a = v1[6];
    std::deque<int>::iterator it = v1.insert(v1.begin() + 2, 3);
    int c = a;
    return a;
}
#包括
int main()
{
std::DEQUEV1={1,3,4,5,7,8,9,1,3,4};
int&a=v1[6];
std::deque::iterator it=v1.insert(v1.begin()+2,3);
int c=a;
返回a;
}
当我运行这个时,结果是9,所以“a”仍然是指正确的元素。
一般来说,我没有设法得到失效错误。我尝试了不同的容器,甚至使用了指针和迭代器。

以下代码,在我的系统上显示了未定义行为的效果

#include <deque>
#include <iostream>

int main()
{
    std::deque<int> v1 = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    for (auto e : v1) std::cout << e << ' ';
    std::cout << std::endl;
    int& a = v1[1];
    int& b = v1[2];
    int& c = v1[3];
    std::cout << a << ' ' << b << ' ' << c << std::endl;
    std::deque<int>::iterator it = v1.insert(v1.begin() + 2, -1);
    for (auto e : v1) std::cout << e << ' ';
    std::cout << std::endl;
    v1[7] = -3;
    std::cout << a << ' ' << b << ' ' << c << std::endl;
    return a;
}
如果引用
a
b
c
仍然有效,则最后一行应该是

2 3 4
请不要由此推断
a
已经失效,而
b
c
仍然有效。它们都是无效的

试试看,也许你是“幸运的”,它也向你展示了同样的东西。如果没有,请在containar中处理元素的数量和一些插入。在某个时候,你可能会看到一些奇怪的事情,比如我的情况

附录


与“simpler”
std::vector
相比,all使失效机制稍微复杂一些。而且你也没有太多的方法来检查某些东西是否真的会受到未定义行为的影响。例如,使用
std::vector
,您可以判断未定义的行为是否会在
推回时刺痛您;实际上,您有成员函数
capacity
,它告诉您容器是否已经有足够的空间容纳通过
向后推
插入更多元素所需的更大的
大小。例如,如果
size
给出8,而
capacity
给出10,则可以
安全地向后推两个元素。如果您再推一个,阵列将不得不重新分配。

有时,可能使某些内容无效的操作不会

我对std::deque实现不太熟悉,因此无法进行评论,但如果您确实将_推回std::vector,例如,您可能会使指向该向量元素的所有迭代器、引用和指针无效,例如,因为std::vector需要分配更多内存来容纳新元素,并最终将所有数据移动到一个新位置,在那里内存可用

或者,由于向量有足够的空间在适当的位置构造新元素,或者幸运地在其当前内存位置的末尾获得了足够的新内存,并且不必移动任何内容,同时仍然更改了大小,因此可能不会使任何内容无效

通常,文档会仔细记录哪些操作会使哪些操作无效。例如,在中搜索“invalidate”

此外,标准数据结构的特定实现可能比标准保证更安全,但依赖于标准保证,代码将变得高度不可移植,并且在潜在的安全保证发生变化时,可能会引入隐藏的错误:在不发生变化之前,一切似乎都正常工作

唯一安全的做法是仔细阅读规范,不要依赖于不能保证失效的东西


此外,正如Enrico所指出的,您可能会遇到引用/指针/迭代器无效的情况,但从中读取会产生一个看起来不错的值,因此,这样一种简单的方法来测试某个内容是否已无效是行不通的。

一般来说,在这样一个简单的例子中,挑起未定义的行为并不一定意味着它会刺痛你。有时,你不会注意到它。这并不意味着恶魔没有从你鼻子里飞出来,只是他们没有造成任何伤害。这一次。垃圾值可能看起来就像正确的值。取消引用无效迭代器总是导致未定义的行为。但是UB可以做任何事情,包括不撞车。@Peanojr,是的,问题在于定义。无效的迭代器/引用/任何意味着您不能安全地使用它的方法,它可能会导致崩溃/错误结果/我的房子被炸,而不是使用它肯定会导致崩溃/错误结果/我的房子被炸。
2 3 4