reserve()-空向量上的data()技巧-是否正确? [英] reserve() - data() trick on empty vector - is it correct?

查看:61
本文介绍了reserve()-空向量上的data()技巧-是否正确?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们知道,std :: vector像 std :: vector vect(n) empty_vect.resize(n)一样初始化时,不仅会分配所需的内存量还要使用默认值对其进行初始化(即调用默认构造函数).这会导致不必要的初始化,尤其是当我有一个整数数组并且我想用一些不能通过任何向量构造函数提供的特定值来填充它时.

另一方面,

容量在调用中分配内存,如 empty_vect.reserve(n),但是在这种情况下,vector仍然为空.因此, size()返回 0 empty()返回 true operator [] 生成异常.

现在,请查看代码:

  {//我的范围从这里开始...std :: vector< int>vect;vect.reserve(n);int * data = vect.data();//在这里,我知道大小为'n',并且我也有数据指针,因此可以将其用作常规数组.//...}//在这里结束了我的范围,因此vector被销毁了,内存被释放了. 

问题是是否可以将其用作数组"是一个安全的假设吗?

不管有什么争论,我只是对以上问题感到好奇.无论如何,关于参数:

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

解决方案

不,您不能使用它.

标准(当前草案,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> ):

 自动数据= std :: unique_ptr< int []> {new int [n]}; 

这将为您提供 std :: unique_ptr< int []> 智能指针,该指针指向动态调整大小的 int 数组,该数组在 data 的生​​存期结束,可以通过移动操作转移其所有权.

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

但是,它没有为您提供 std :: vector 接口.特别是,它不提供对其分配大小的访问权限,因此无法复制.


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

As we know, std::vector when initialized like std::vector vect(n) or empty_vect.resize(n) not only allocates required amount of memory but also initializes it with default value (i.e. calls default constructor). This leads to unnecessary initialization especially if I have an array of integers and I'd like to fill it with some specific values that cannot be provided via any vector constructor.

Capacity on the other hand allocates the memory in call like empty_vect.reserve(n), but in this case vector still is empty. So size() returns 0, empty() returns true, operator[] generates exceptions.

Now, please look into the code:

{ // 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.

The question is if "so I can use it as array" is a safe assumption?

No matter for arguments, I am just curious of above question. Anyway, as for arguments:

  1. It allocates memory and automatically frees it on any return from function
  2. Code does not performs unnecessary data initialization (which may affect performance in some cases)

解决方案

No, you cannot use it.

The standard (current draft, equivalent wording in C++11) says in [vector.data]:

constexpr T* data() noexcept;

constexpr const T* data() const noexcept;

Returns: A pointer such that [data(), data() + size()) is a valid range. For a non-empty vector, data() == addressof(front()).

You don't have any guarantee that you can access through the pointer beyond the vector's size. In particular, for an empty vector, the last sentence doesn't apply and so you cannot even be sure that you are getting a valid pointer to the underlying array.

There is currently no way to use std::vector with default-initialized elements.


As mentioned in the comments, you can use std::unique_ptr instead (requires #inclue<memory>):

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

which will give you a std::unique_ptr<int[]> smart pointer to a dynamically sized array of int's, which will be destroyed automatically when the lifetime of data ends and that can transfer it's ownership via move operations.

It can be dereferenced and indexed directly with the usual pointer syntax, but does not allow direct pointer arithmetic. A raw pointer can be obtained from it via data.get().

It does not offer you the std::vector interface, though. In particular it does not provide access to its allocation size and cannot be copied.


Note: I made a mistake in a previous version of this answer. I used std::make_unique<int[]> without realizing that it actually also performs value-initialization (initialize to zero for ints). In C++20 there will be std::make_unique_default_init<int[]> which will default-initialize (and therefore leave ints with indeterminate value).

这篇关于reserve()-空向量上的data()技巧-是否正确?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆