2013-08-27 3 views
6

Если вам не нужен динамический рост и не знаю размер буфера во время компиляции, когда следует использовать unique_ptr<int[]> вместо vector<int>, если вообще?unique_ptr <int[]> или vector <int>?

Есть ли существенная потеря производительности при использовании vector вместо unique_ptr?

+10

Почему бы не использовать std :: array? – Bart

+5

@Bart Ему не нужно увеличивать объем хранилища, если он был выделен, это не значит, что он знает размер во время компиляции. – Praetorian

+0

@Bart Я обновил вопрос, чтобы предположить, что размер буфера неизвестен во время компиляции. – huitlarc

ответ

4

Там нет потери производительности при использовании std::vector vs. std::unique_ptr<int[]>. Альтернативы не совсем эквивалентны, поскольку, поскольку вектор можно выращивать, а указатель не может (это может быть и преимущество или недостаток, сделал ли вектор по ошибке?)

Существуют и другие отличия, такие как тот факт, что значения будут инициализированы в std::vector, но их не будет, если вы используете new массив (если вы не используете инициализацию значения ...).

В конце дня я лично предпочел бы std::vector<>, но я все еще код на C++ 03 без std::unique_ptr.

+0

Кроме того, давайте не будем забывать, что с методом 'unique_ptr' нет информации о размере. –

4

C++ 14 представляет для этой цели std :: dynarray.

Теперь между этими двумя конструкциями:

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

Первый дает неинициализированный массив междунар но второй инициализирует его значением (0, если не обеспечить). Так что, если вам не нужна память для инициализации, потому что вы будете переписывать его как-то позже с чем-то более сложным, чем std::fill, выберите 1, если нет, выберите 2.

+6

C++, чем вы стали ... – GManNickG

+4

Я думал, что «dynarray» был представлен программистам Croll C++. –

+0

@Mystical История за 'dynarray' более тонкая, чем базовый тролль. Для этого требуется не столько умение писать базовый 'dynarray' как фиксированный размер' vector' со стандартным динамическим распределением. Но реальная тайна этого объекта заключается в том, чтобы позволить компилятору решить, где выделять память, она может находиться в куче, но может быть в стеке. И это невозможно сделать даже с C++ 11. – galop1n

3

std::vector сохраняет длину как размера переменной, так и размера выделенных данных вместе с указателем на данные, которые он сам. std::unique_ptr просто хранит указатель, поэтому может быть небольшое увеличение при использовании std::unique_ptr.

Никто еще не упомянул, что вектор предоставляет итераторы и функции, такие как size(), где в качестве уникального ptr нет. Так что, если итераторы нуждающегося использования std::vector

1

Цель Часть:

Нет, вероятно, не должно быть существенной разницы в производительности между этими двумя (хотя я предполагаю, что это зависит от реализации, и вы должны измерить, если это важно) ,

Субъективная часть:

std::vector собирается дать вам хорошо известный интерфейс с .size() и .at() и итераторы, которые будут играть хорошо со всеми видами другого кода. Использование std::unique_ptr дает вам более примитивный интерфейс и позволяет вам отслеживать детали (например, размер) отдельно. Поэтому, запрещая другие ограничения, я бы предпочел std::vector.

6

Если вы находитесь в положении, где vector<int> - это даже возможность, вы, вероятно, захотите пойти с этим, кроме крайних и редких обстоятельств.И даже в этом случае наилучшим ответом может быть нестандартный тип вместо unique_ptr<int[]>.

Так что же это за unique_ptr<int[]>? :-)

unique_ptr<T[]> действительно сияет в двух случаях:

1. Вы должны обрабатывать таНос/свободный ресурс из некоторой унаследованной функции, и вы хотели бы сделать это в современном исключения безопасного стиля:

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. вы нужно временно закрепить новый [] ресурс перед передачей его на другой владелец:

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 
    } 
}; 

В приведенном выше сценарии X владеет переданным ему указателем, успешно ли конструктор или нет. В этом конкретном примере используется конструктор по умолчанию noexcept для std::string, который не является обязательным. Однако:

  1. Эта точка обобщается по обстоятельствам, не связанным с std::string.
  2. A std::string Конструктор по умолчанию, который выбрасывает, является хромым.
Смежные вопросы