【问题标题】:C++ STL Containers and pointer validityC++ STL 容器和指针有效性
【发布时间】:2010-12-05 09:07:07
【问题描述】:

考虑这段代码:

Uint counter = 0;

int* p1;
int* p2;

deque<int>  dequeInstance;
vector<int> vectorInstance;

dequeInstance.push_back(3);
dequeInstance.push_back(7);

p1 = &dequeInstance.back();

dequeInstance.push_back(17);

p2 = &dequeInstance.back();

if(*p1 == !7)
    ++counter;

if(*p2 == !17)
    ++counter;

vectorInstance.push_back(3);
vectorInstance.push_back(7);

p1 = &vectorInstance.back();

vectorInstance.push_back(17);

p2 = &vectorInstance.back();

if(*p1 == !7)
    ++counter;

if(*p2 == !17)
    ++counter;



return counter;

我原以为当我将第三个元素推到向量的后面时,指向第二个元素的指针会失效,因为我对 std::vector 的理解是它是一个被擦除的直数组,并且每次修改时都会重新创建。然而,在这段代码的末尾,'counter' 等于 0。

我在这里错过了什么?

【问题讨论】:

    标签: c++ pointers stl


    【解决方案1】:

    希望出于性能考虑,std::vector 不会“在每次修改时都被擦除和重新创建”。

    一个向量有一个capacity,它可能超过它的size,这意味着它可以分配比实际使用更多的内存。当您push_back 时,仅当新大小大于旧容量时才会发生重新分配,并且在这种情况下,迭代器无效。

    在您的情况下,您应该在 std::vector 实例化之后立即检查 capacity 的值。您会看到它毫无疑问大于 3,因此,您的任何 push_back 调用都不会触发重新分配,并且所有迭代器都保持有效。

    还要注意std::vector 提供了一个reserve 成员函数,它允许您控制向量容量。当您知道要插入多少个元素以避免不为人知的重新分配时,这非常有用。

    【讨论】:

    • 标准保证push_back的摊销常数时间。这意味着vector 不可能每次都调整大小。希望在这里不是必需的:)
    【解决方案2】:

    好的,你有一些问题。首先,!n = 0 除非 n = 0,然后它等于 1。因此计数器永远不会增加。

    其次,当你 push_back 一个新元素时,向量不一定会破坏内容。一个向量有 2 个“大小”。 1 是向量中的元素数,2 是分配的内存量。向量只有在分配的内存量用完时才会重新分配和复制。

    此外,在您删除内存区域后,内存不一定会被清除,并且可能仍指向有效数据。

    您没有使用迭代器,因此它们不会失效。您正在使用指针,它们只是指向内存区域。仅仅因为没有分配内存并不意味着指针无效。这是 C/C++ 可能给您带来的主要危险之一。确保你不要做这样的事情,因为你正在调用“未定义的行为”,它可以做任何事情,从“不会导致任何问题并且看似有效”到“可怕地崩溃并以危险的方式关闭你的操作系统”。

    【讨论】:

    • 哎呀!这意味着!=。我正在重新输入我早上写的内容。我需要睡觉。
    • @Tomas:好吧,无论如何,计数器永远不会增加,因为指针要么仍然指向有效数据,要么指向内存和未定义的行为,在你的情况下,看到这些值分配返回堆后仍保留在内存中...
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-28
    • 2011-07-08
    相关资源
    最近更新 更多