reserve() - data() trick on empty vector - is it correct?

无人久伴 提交于 2021-02-04 19:34:05

问题


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)

回答1:


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).



来源:https://stackoverflow.com/questions/59421717/reserve-data-trick-on-empty-vector-is-it-correct

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!