Есть ли польза от unique_ptr с массивом?

В std::unique_ptr есть поддержка массивов, например:

std::unique_ptr<int[]> p(new int[10]);

но нужна ли она? Возможно, удобнее использовать std::vector или std::array.

Находите ли вы применение этой конструкции?

Комментарии к вопросу (2)
Решение

Некоторые люди не могут позволить себе использовать std::vector, даже с аллокаторами. Некоторым нужен динамически изменяемый размер массива, поэтому std::array не подходит. А некоторые люди получают свои массивы из другого кода, который, как известно, возвращает массив; и этот код не будет переписан для возврата vector или чего-то подобного.

Разрешая unique_ptr, вы удовлетворяете эти потребности.

Короче говоря, вы используете unique_ptr, когда вам это нужно. Когда альтернативные варианты просто не подходят. Это инструмент последнего средства.

Комментарии (22)

Есть компромиссные варианты, а вы выбираете решение, которое соответствует тому, что вы хотите. С верхней части моей головы:

Начальный размер

  • вектор и unique_ptr не<Т[]> чтобы размер будет определен во время выполнения
  • массив только позволяет размер будет определен во время компиляции

Изменение размера

  • время и unique_ptr не<Т[]> не допустить изменения размера
  • "вектор" делает

Хранение

  • вектор и unique_ptr не<Т[]> хранить данные за пределами объекта (обычно в куче)
  • массив хранит данные непосредственно в объекте

Копирование

  • массив и вектор разрешить копирование
  • `unique_ptr не<Т[]> не допускать копирования

Замена/перемещение

  • вектор и unique_ptr не<Т[]> за O(1) времени своп и ход операции
  • массива имеет сложность o(n) времени своп и ход операций, где n-количество элементов в массиве

Указатель/ссылку/итератор недействительным

  • массив обеспечивает указатели, ссылки и итераторы никогда не будут аннулированы, пока объект жив, даже на своп()
  • unique_ptr не<Т[]> не имеет итераторы; указатели и ссылки являются лишь законной силы своп() пока объект жив. (После замены, указатели точку в массив, который вы заменили, так они'вновь еще "не действует" в этом смысле.)
  • "вектор" может привести к аннулированию указатели, ссылки и итераторы на любое перераспределение (и предоставляет некоторые гарантии, что перераспределение может происходить только на определенной операции).

Совместимость с понятий и алгоритмов

  • время и вектор оба контейнеры
  • unique_ptr не<Т[]> это не контейнер

Я должен признать, это выглядит как возможность для небольшого рефакторинга с учетом политики дизайна.

Комментарии (11)

Одна из причин, вы могли бы использовать `unique_ptr не является если вы Don'т хотите оплатить стоимость выполнения значение-инициализация массива.

std::vector vec(1000000); // allocates AND value-initializes 1000000 chars

std::unique_ptr p(new char[1000000]); // allocates storage for 1000000 chars

В СТД::векторконструкторСТД::вектор::размер () будет значение-инициализировать т - но "новые" не будут этого делать, если Т представляет собой стручок.

См https://stackoverflow.com/questions/15097783/value-initialized-objects-in-c11-and-stdvector-constructor

Обратите внимание, что `вектор::заповедник-это не альтернатива здесь: https://stackoverflow.com/questions/8228072/is-accessing-the-raw-pointer-after-stdvectorreserve-safe

Это'с той же причине C программист может выбрать функция malloc за памятью.

Комментарии (4)

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

Комментарии (10)

Скотт Мейерс рассказывает в эффективный современный c++

существование с std::unique_ptr не для массивов должны быть только интеллектуальный интерес к вам, потому чтос std::массив, СТД::вектор,СТД::строкапрактически всегда лучше, выбор структуры данных, чем сырые массивы. О единственной ситуации я могу понять, когдас std::unique_ptr не<Т[]>` имело бы смысл будет, когда вы're с помощью СИ-подобного API, который возвращает сырой указатель на куче массива, вы берете на себя право собственности.

Я думаю, что Чарльз сальвии'ы ответьте хотя актуален:, что с std::unique_ptr не<Т[]> это единственный способ, чтобы инициализировать пустой массив, чей размер не известен во время компиляции. Что бы Скотт Мейерс нужно сказать о такой мотивации, используя с std::unique_ptr не<Т[]>?

Комментарии (1)

Вопреки СТД::векторис std::массив,с std::unique_ptr не может иметь нулевой указатель. Это пригодится при работе с API-интерфейсы c, ожидающие или массив или null:

void legacy_func(const int *array_or_null);

void some_func() {    
    std::unique_ptr ptr;
    if (some_condition) {
        ptr.reset(new int[10]);
    }

    legacy_func(ptr.get());
}
Комментарии (0)

Я использовал unique_ptr для реализации пулов предварительно распределенной памяти, используемых в игровом движке. Идея заключается в том, чтобы предоставить предварительно распределенные пулы памяти, используемые вместо динамического распределения для возврата результатов запросов столкновений и других вещей, таких как физика частиц, без необходимости выделять / освобождать память в каждом кадре. Это довольно удобно для такого рода сценариев, где вам нужны пулы памяти для размещения объектов с ограниченным временем жизни (обычно один, 2 или 3 кадра), которые не требуют логики уничтожения (только деаллокация памяти).

Комментарии (0)

В двух словах: это'ы на сегодняшний день наиболее эффективный для памяти.

В СТД::строкапоставляется с указателем, длинну, и на "короткие строки-оптимизация и" буфера. Но моя ситуация мне нужно сохранить строку, которая почти всегда пустая, в структуру, которая у меня сотни тысяч. В C, я бы просто использоватьchar и, и было бы нуль большую часть времени. Который работает для C++, тоже, за исключением того, чтоchar и не имеет деструктора, а не&#39;т знаем, чтобы удалить себя. Напротив,с std::unique_ptr не<символ[]>будет удалить себя, когда он выходит из области видимости. ПустойСТД::строказанимает 32 байта, но пустойс std::unique_ptr не<символ[]>` занимает 8 байт, то есть ровно на размер указателя.

Самый большой недостаток в том, что каждый раз, когда я хочу знать длину строки, Мне нужно позвонить функция strlen на нем.

Комментарии (1)

Общий шаблон может быть найден в [некоторых][GetPackageApplicationIds_MSDN] ОС Windows API-интерфейса Win32 звонки, в которых использование с std::unique_ptr не<Т[]> может пригодиться, например, когда вы Don'т знаю, насколько большой буфер вывода должен быть при вызове некоторые Win32 API (так что буду писать некоторые данные в буфер):

// Buffer dynamically allocated by the caller, and filled by some Win32 API function.
// (Allocation will be made inside the 'while' loop below.)
std::unique_ptr buffer;

// Buffer length, in bytes.
// Initialize with some initial length that you expect to succeed at the first API call.
UINT32 bufferLength = /* ... */;

LONG returnCode = ERROR_INSUFFICIENT_BUFFER;
while (returnCode == ERROR_INSUFFICIENT_BUFFER)
{
    // Allocate buffer of specified length
    buffer.reset( BYTE[bufferLength] );
    //        
    // Or, in C++14, could use make_unique() instead, e.g.
    //
    // buffer = std::make_unique(bufferLength);
    //

    //
    // Call some Win32 API.
    //
    // If the size of the buffer (stored in 'bufferLength') is not big enough,
    // the API will return ERROR_INSUFFICIENT_BUFFER, and the required size
    // in the [in, out] parameter 'bufferLength'.
    // In that case, there will be another try in the next loop iteration
    // (with the allocation of a bigger buffer).
    //
    // Else, we'll exit the while loop body, and there will be either a failure
    // different from ERROR_INSUFFICIENT_BUFFER, or the call will be successful
    // and the required information will be available in the buffer.
    //
    returnCode = ::SomeApiCall(inParam1, inParam2, inParam3, 
                               &bufferLength, // size of output buffer
                               buffer.get(),  // output buffer pointer
                               &outParam1, &outParam2);
}

if (Failed(returnCode))
{
    // Handle failure, or throw exception, etc.
    ...
}

// All right!
// Do some processing with the returned information...
...

[GetPackageApplicationIds_MSDN]: http://msdn.microsoft.com/en-us/library/windows/desktop/dn270603(В=и 85).аспн

Комментарии (2)

Я столкнулся с такой случай, когда я должен был использовать с std::unique_ptr не<типа bool [] и GT;, который был в HDF5 библиотека (библиотека для эффективное бинарное хранение данных, используемый много в науке). Некоторые компиляторы (в Visual Studio 2015 в моем случае) обеспечивают сжатие СТД::вектор<типа bool и GT; (с помощью 8 значений в каждый байт), что является катастрофой для что-то вроде HDF5, который не'т волнует, что сжатие. С СТД::вектор<типа bool и GT;`, HDF5 был в конце концов читать мусор из-за этого сжатия.

Угадайте, кто был там для спасения, в случае, когда СТД::вектор` ничего't работа, и мне нужно выделить динамический массив чисто? :-)

Комментарии (0)

Еще одна причина, чтобы разрешить и использовать с std::unique_ptr не<Т [] и GT;`, что еще'т было упомянуто в ответах до сих пор: она позволяет вперед-объявить тип элемента массива.

Это полезно, когда вы хотите минимизировать прикованный #включить высказывания в заголовках (оптимизировать производительность построения.)

Например

класса MyClass.ч:

class ALargeAndComplicatedClassWithLotsOfDependencies;

class MyClass {
   ...
private:
   std::unique_ptr m_InternalArray;
};

myclass.cpp:

#include "myclass.h"
#include "ALargeAndComplicatedClassWithLotsOfDependencies.h"

// MyClass implementation goes here

С помощью данной структуры кода, кто может #включить и"класса MyClass.ч" В и использовать класса MyClass, без включения внутренних зависимостей, необходимых для осуществления класса MyClass::m_InternalArray.

Если m_InternalArrayбыл объявлен какс std::массив, илиСТД::вектор<...>`, соответственно - результат был бы покушение на использование неполного типа, что ошибка времени компиляции.

Комментарии (1)

Чтобы ответить на людей, думая, что вы "не надо" и использовать вектор вместо unique_ptr не у меня есть дело в программирования CUDA на GPU при выделении памяти в устройство необходимо зайти на массив указателей (с cudaMalloc). Затем, при получении этих данных в хост, нужно идти снова на указатель иunique_ptr неэто хорошо, чтобы легко справиться указатель. Дополнительных затрат на преобразование двойных* в вектор<двойной> является ненужным и приводит к потере производительности.

Комментарии (0)
  • Вам нужна ваша структура содержит только указатель для бинарной совместимости.
  • Вы должны взаимодействовать с API, который возвращает память, выделенную с помощью New[]`
  • Ваша фирма или проект имеет общее правило против использования СТД::вектор, например, для предотвращения неосторожного программиста от случайного представляем копии
  • Вы хотите предотвратить нерадивых программистов из случайно представляем копии в данном случае.

Есть общее правило, что c++ контейнеры должны быть предпочтительнее, чем прокатки свой собственный с указателями. Это общее правило, которое не имеет исключений. Там's больше, это лишь примеры.

Комментарии (0)

Они могут быть верным ответ можно получить только ткнуть указателем через существующий API (думаю окне сообщений или потоков, связанных с обратного вызова, параметры), которые имеют определенную продолжительность жизни после того, как "поймали" на другую сторону люка, но который никакого отношения к вызывающему коду:

unique_ptr data = get_some_data();

threadpool->post_work([](void* param) { do_a_thing(unique_ptr((byte*)param)); },
                      data.release());

Мы все хотим, чтобы все было хорошо для нас. C++ - это для другого раза.

Комментарии (0)

unique_ptr не<символ[]> может быть использована там, где требуется производительность и удобство работы с C++. Считаю нужно работать на миллионы (если не миллиарды, если вы Don'т доверять еще) строк. Хранение каждого из них в отдельную строку или вектор<чар>` объект станет катастрофой для памяти (кучи) режимы управления. Особенно, если вам нужно выделить и удалить разные строки много раз.

Тем не менее, можно выделить один буфер для хранения, что много строк. Вы бы'т, как типа char* буфер = (тип char*)Танос(total_size); по понятным причинам (если не очевидно, поиск по "Почему использовать смарт-ПТРС-то"). Вы бы как unique_ptr не<типа char[]> буфер(новая Чаре[total_size]);

По аналогии, такую же производительность&соображения удобства применяется для данных типа char`(считают миллионы векторов/матриц/объекты).

Комментарии (1)

Если вам нужен динамический массив объектов, которые не копируют-конструктивны, то умный указатель на массив является способом пойти. Например, что если вам нужен массив атомной и Л;int>В С.

Комментарии (0)