unique_ptr or vector?

2020-02-10 04:19发布

问题:

If you don't need dynamic growth and don't know the size of the buffer at compile time, when should unique_ptr<int[]> be used instead of vector<int> if at all?

Is there a significant performance loss in using vector instead of unique_ptr?

回答1:

There is no performance loss in using std::vector vs. std::unique_ptr<int[]>. The alternatives are not exactly equivalent though, since the vector could be grown and the pointer cannot (this can be and advantage or a disadvantage, did the vector grow by mistake?)

There are other differences, like the fact that the values will be initialized in the std::vector, but they won't be if you new the array (unless you use value-initialization...).

At the end of the day, I personally would opt for std::vector<>, but I still code in C++03 without std::unique_ptr.



回答2:

If you're in a position where vector<int> is even a possibility, you probably want to go with that except in extreme and rare circumstances. And even then, a custom type instead of unique_ptr<int[]> may well be the best answer.

So what the heck is unique_ptr<int[]> good for? :-)

unique_ptr<T[]> really shines in two circumstances:

1. You need to handle a malloc/free resource from some legacy function and you would like to do it in a modern exception safe style:

void
foo()
{
    std::unique_ptr<char[], void(*)(void*)> p(strdup("some text"), std::free);
    for (unsigned i = 0; p[i]; ++i)
        std::cout << p[i];
    std::cout << '\n';
}

2. You've need to temporarily secure a new[] resource before transferring it onto another owner:

class X
{
    int* data_;
    std::string name_;

    static void validate(const std::string& nm);
public:
    ~X() {delete [] data_;}

    X(int* data, const std::string& name_of_data)
        : data_(nullptr),
          name_()
    {
        std::unique_ptr<int[]> hold(data);  // noexcept
        name_ = name_of_data;               // might throw
        validate(name_);                    // might throw
        data_ = hold.release();             // noexcept
    }
};

In the above scenario, X owns the pointer passed to it, whether or not the constructor succeeds. This particular example assumes a noexcept default constructor for std::string which is not mandated. However:

  1. This point is generalizable to circumstances not involving std::string.
  2. A std::string default constructor that throws is lame.


回答3:

std::vector stores the length of both the size of the variable and the size of the allocated data along with the pointer to the data it's self. std::unique_ptr just stores the pointer so there may be a small gain in using std::unique_ptr.

No one has yet mentioned the vector provides iterators and function such and size() where as unique ptr does not. So if iterators are needed use std::vector



回答4:

C++14 introduces std::dynarray for that purpose.

Now, between these two constructions :

  1. auto buffer = std::make_unique<int[]>( someCount );
  2. auto buffer = std::vector<int>( someCount, someValue );

The first gives you an uninitialized array of int but the second initializes it with a value ( 0 if not provide ). So if you do not need the memory to be initialized because you will overwrite it somehow later with something more complex than std::fill, choose 1, if not, choose 2.



回答5:

Objective Part:

No, there probably shouldn't be a significant performance difference between the two (though I suppose it depends on the implementation and you should measure if it's critical).

Subjective Part:

std::vector is going to give you a well known interface with .size() and .at() and iterators, which will play nicely with all sorts of other code. Using std::unique_ptr gives you a more primitive interface and makes you keep track of details (like the size) separately. Therefore, barring other constraints, I would prefer std::vector.