[Followup на this вопрос]Инициализация shared_ptr <T> из unique_ptr <T[]>
Я занимаюсь немного со смарт-указатели на массивы с стиле в последнее время. Я в конечном итоге закончил делать рекомендуемую вещь и вместо этого использовал интеллектуальные указатели для векторов, но в течение этого периода я получил немного советов: не используйте объект shared_ptr<T>
для управления массивом, изначально сделанным с make_unique<T[]>
, потому что он не будет звонить delete[]
а скорее delete
.
Это не кажется логичным для меня, и я проверил как Coliru и стандарт:
Этот код:
#include <iostream>
#include <memory>
int main()
{
std::cout << "start!\n";
auto customArrayAllocator = [](unsigned int num){
std::cout << "custom array allocator\n";
return new int[num];
};
std::cout << "allocator constructed\n";
auto customArrayDeleter = [](int *ptr){
std::cout << "custom array deleter\n";
delete[] ptr;
};
std::cout << "deleter constructed\n";
std::unique_ptr<int[], decltype(customArrayDeleter)>
myUnique(customArrayAllocator(4), customArrayDeleter);
std::cout << "unique_ptr constructed\n";
std::shared_ptr<int>
myShared = std::move(myUnique);
std::cout << "shared_ptr constructed\n";
}
производит этот выход:
start!
allocator constructed
deleter constructed
custom array allocator
unique_ptr constructed
shared_ptr constructed
custom array deleter
Который, по-видимому, указывает, что делетер unique_ptr<T[]>
передан в shared_ptr<T>
, как я и ожидал.
от стандартного § С ++ 14 20.8.2.2.1 pg. 571 of doc, 585 of pdf
шаблон shared_ptr (unique_ptr & & г);
Примечание: Этот конструктор не должен участвовать в разрешении перегрузки, если уникальный_ptr :: указатель не может быть конвертирован в T *.
Эффекты: Эквивалент shared_ptr (r.release(), r.get_deleter()), когда D не является ссылочным типом, иначе shared_ptr (r.release(), ref (r.get_deleter())).
Безопасность исключений: Если выбрано исключение, конструктор не имеет эффекта.
Если я читаю это право, это означает, что shared_ptr
объект строит себя как от указателя и Deleter в виде unique_ptr
. Кроме того, я понимаю (от ответа на исходный вопрос), что тип unique_ptr<T[]>
- T*
, который должен быть конвертирован в shared_ptr<T>::pointer
's T*
. Таким образом, отладчик должен быть скопирован прямо из объекта unique_ptr
, верно?
ли мой тест работает только потому, что это на самом деле не эквивалентна функции std::make_shared<T[]>
или синтаксис
std::shared_ptr<T> mySharedArray = std::make_unique<T[]>(16);
хорошее, исключение безопасно (и чище) альтернатива
std::shared_ptr<T> mysharedArray(new T[16], [](T* ptr){delete[] ptr;});
и т. Д., Когда я не могу использовать Boost shared array и желаю избегать включения либо vector
, либо array
hea с моим кодом?
N.B. хотя массив гарантированно будет удален, существует потенциальная проблема безопасности при преобразовании 'unique_ptr' -> 'shared_ptr ' -> 'shared_ptr ', см. http://stackoverflow.com/q/32483375/981959 –