首页 > 解决方案 > 保留() - 空向量上的数据()技巧 - 正确吗?

问题描述

众所周知,std::vector 在初始化时std::vector vect(n)不仅empty_vect.resize(n)会分配所需的内存量,还会使用默认值初始化它(即调用默认构造函数)。这会导致不必要的初始化,特别是如果我有一个整数数组并且我想用一些无法通过任何向量构造函数提供的特定值填充它。

另一方面,容量在调用中分配内存empty_vect.reserve(n),但在这种情况下,向量仍然是空的。所以size()返回0empty()返回trueoperator[]产生异常。

现在,请查看代码:

{ // My scope starts here...

    std::vector<int> vect;
    vect.reserve(n);
    int *data = vect.data();

    // Here I know the size 'n' and I also have data pointer so I can use it as a regular array.
    // ...

} // Here ends my scope, so vector is destroyed, memory is released.

问题是“所以我可以将它用作数组”是否是一个安全的假设?

不管争论,我只是对上述问题感到好奇。无论如何,至于论点:

  1. 它分配内存并在函数返回时自动释放它
  2. 代码不执行不必要的数据初始化(在某些情况下可能会影响性能)

标签: c++c++11stl

解决方案


不,你不能使用它。

标准(当前草案,C++11 中的等效措辞)在 [vector.data] 中说

constexpr T* data() noexcept;

constexpr const T* data() const noexcept;

返回[data(), data() + size())一个有效范围的指针。对于非空向量,data() == addressof(front())

您无法保证可以通过超出向量大小的指针进行访问。特别是,对于一个空向量,最后一句话不适用,因此您甚至无法确定您是否获得了指向底层数组的有效指针。

当前无法使用std::vector默认初始化的元素。


如评论中所述,您可以std::unique_ptr改用(需要#inclue<memory>):

auto data = std::unique_ptr<int[]>{new int[n]};

这将为您提供一个std::unique_ptr<int[]>指向动态大小的数组的智能指针,该数组int将在生命周期结束时自动销毁,data并且可以通过移动操作转移其所有权。

它可以使用通常的指针语法直接取消引用和索引,但不允许直接指针算术。可以通过 从中获取原始指针data.get()

但是,它没有为您提供std::vector界面。特别是它不提供对其分配大小的访问,并且不能被复制。


注意:我在此答案的先前版本中犯了一个错误。我使用std::make_unique<int[]>时没有意识到它实际上也执行值初始化(对于ints 初始化为零)。在 C++20 中std::make_unique_default_init<int[]>,将默认初始化(因此使ints 具有不确定的值)。


推荐阅读