【问题标题】:Does resizing an STL vector erase/invalidate its previous contents?调整 STL 向量的大小是否会擦除/使其先前的内容无效?
【发布时间】:2012-03-06 21:00:34
【问题描述】:

它似乎不是(示例程序),但我可以确定吗?

// does resizing an STL vector erase/invalidate it's previous contents?
#include <stdio.h>
#include <vector>
using namespace std ;

void print( vector<int>& t )
{
  for( int i = 0 ; i < t.size() ; i++ )
    printf( "%d ", t[i] ) ;
  puts("");
}

int main()
{
  vector<int> t ;
  t.resize( 12,9999 ) ;
  print(t) ;

  t.resize( 15, 10000 ) ;
  print(t) ;
}

【问题讨论】:

  • “无效”是什么意思?
  • @Xeo:例如,在正确的程序中可能无法访问“无效的迭代器”。调整 std::vector 的大小会使其所有迭代器无效。 (调整 std::list 的大小不会。)
  • @Dietrich:我知道这一点,但是 OP 的代码没有显示任何这些,所以我想知道这里的“无效”到底是什么意思。也可能是 OP 认为以前的项目将被重置/擦除/任何东西。

标签: c++ stl vector


【解决方案1】:

调整 STL 向量的大小可能需要重新分配底层存储。这可能导致任意数量的元素被销毁和重新创建,并且所有迭代器都失效。使用 STL 时访问失效的迭代器是常见的错误来源。 p>

每个元素的内容都是一样的,除非复制构造函数不起作用。

int main(int argc, char *argv[])
{
    int data[] = { 1, 2, 3 };

    std::vector vec(data, data + 3);
    // vector contains 1, 2, 3

    std::vector::iterator i = vec.begin();
    cout << *i << endl; // prints 1
    int &ref = *i;
    cout << ref << endl; // prints 1

    vec.resize(6, 99);
    // vector now contains 1, 2, 3, 99, 99, 99

    // WRONG! may crash, may do the wrong thing, might work...
    // cout << *i << endl;

    // WRONG! invalid reference
    // cout << ref << endl;

    return 0;
}

【讨论】:

  • 具体来说,如果将向量调整为较小的大小,则只有删除元素的迭代器无效。如果将向量调整为更大的大小,但仍小于 capacity() 的值,则不会发生迭代器失效(标准禁止这样做)。如果将向量的大小增加到大于容量的值,则向量元素的所有迭代器都将失效()。
  • @Kemin:这是不正确的。保留向量中的元素并不意味着迭代器在调整大小后仍然有效。您链接的页面中暗示了这一点:“当调整为较小的大小时,向量容量永远不会减少,因为这会使所有迭代器失效……”事实上,只要向量容量发生变化,all 迭代器就会失效,无论它变大还是变小。如果你仔细想想,一个指向向量的迭代器基本上只是一个指向元素的指针,所以当然是这样的。
  • @Kemin:请参阅en.cppreference.com/w/cpp/container/vector 中名为“迭代器失效”的部分。奇怪的是各个函数页面都没有提到失效,但是在std::vector页面上清楚地写明了所有迭代器在容量变化时都被resize失效。
  • 迪特里希,你是对的。保留的是值,而不是引用(指针、迭代器)(移动到不同的内存位置)。对不起,没有彻底。
【解决方案2】:

当且仅当新大小大于容器的当前容量(即v.capacity())时,resize 将使所有迭代器、指针和对 std::vector 的引用无效。

容器中的元素永远不会“失效”。如果您将容器的大小调整为小于其当前大小,则任何超出新大小的额外元素都将被销毁。

如果您调整容器的大小以使新大小大于当前容量,并且需要重新分配底层存储,则所有元素都会被复制或移动到新分配的存储中。当你放大一个容器时,之前的元素总是被保留,只是移动或复制到内存中的新位置。

【讨论】:

    【解决方案3】:

    调整向量的大小不会破坏存储在向量中的值(当然,缩小时超出新大小的值除外),但是超出其容量的向量会复制(或者,在 C++11 中,移动) 将它们移到一个新位置,从而使这些元素的迭代器、指针或引用无效。

    在您的示例程序中,您不会在调整大小期间存储迭代器、指针或对向量元素的引用,因此如果在调整大小期间复制了数据,您将访问复制的值(这很可能,但不完全确定;向量可能为超过所需元素分配空间;实际上,在增长时,它经常必须这样做以满足复杂性要求)。

    您可以通过成员函数capacity 获取当前容量(在需要重新分配之前可以将其增长到的元素数量)。只要向量的增长不超过当前容量,即使是迭代器、指针和对存储对象的引用也是安全的。此外,如果您想确保没有迭代器、指针或引用无效,并且您事先知道向量可能增长到的最大大小,那么您可以使用成员函数 reserve 预分配所有需要的内存。

    【讨论】:

      【解决方案4】:

      调整大小会尽可能多地复制数据。看看这个http://www.cplusplus.com/reference/stl/vector/resize/

      【讨论】:

      【解决方案5】:

      内容仍然存在。如果您的向量容量为 1000,其中包含 500 个元素,并且您将大小调整为 2000,则将复制所有 500 个元素。如果将其调整为 200,则只会复制前 200 个元素,而删除后 300 个元素。

      【讨论】:

        【解决方案6】:

        有一个例子Here

        当您调整到更大的尺寸时,它只会用该值填充新单元格。

        【讨论】:

          猜你喜欢
          • 2010-12-10
          • 2014-10-23
          • 1970-01-01
          • 1970-01-01
          • 2020-10-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-04-02
          相关资源
          最近更新 更多