2015-05-28 24 views
8

[Nawiązanie do this Pytanie]Inicjacja shared_ptr <T> z unique_ptr <T[]>

Byłem trochę do czynienia z inteligentnymi wskaźniki do tablic c stylu niedawno. Ostatecznie nakręciłem zalecaną rzecz i zamiast tego użyłem inteligentnych wskaźników do wektorów, ale w tym okresie mam trochę rad: nie używaj obiektu shared_ptr<T> do zarządzania tablicą początkowo wykonaną przy użyciu make_unique<T[]>, ponieważ nie będzie ona wywoływać delete[] ale raczej delete.

To nie wydaje się logiczne, aby mnie i sprawdzone zarówno Coliru a średnia:


ten kod:

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

produkuje ten wyjściowe:

start! 
allocator constructed 
deleter constructed 
custom array allocator 
unique_ptr constructed 
shared_ptr constructed 
custom array deleter 

Co wydaje się wskazywać, że delikator unique_ptr<T[]> jest przekazywany do shared_ptr<T>, jak się spodziewałem.


Z C++ 14 standardowych § 20.8.2.2.1 pg. 571 of doc, 585 of pdf

szablon shared_ptr (unique_ptr & & r);
Uwaga: Ten konstruktor nie uczestniczy w przeciążeniu, chyba że unikalny_ptr :: wskaźnik jest zamienny na T *.
Wpływ: odpowiednik shared_ptr (r.release() r.get_deleter()), jeśli D nie jest typu odniesienia inaczej shared_ptr (r.release() Ref (r.get_deleter())).
Bezpieczeństwo wyjątków: Jeśli zostanie zgłoszony wyjątek, konstruktor nie wywoła żadnego efektu.

Jeśli czytam tego prawa, to znaczy, że shared_ptr obiekt buduje się zarówno wskaźnik i Deleter z unique_ptr. Ponadto, to moje zrozumienie (z odpowiedzi na oryginalne pytanie), że ::pointer typu unique_ptr<T[]> jest T*, który powinien być zamienny na 's T*. Deleter powinien być po prostu skopiowany bezpośrednio z obiektu unique_ptr, prawda?


Czy moja próba pracy tylko dlatego, że nie jest właściwie równoznaczne z funkcji std::make_shared<T[]>, czy składnia

std::shared_ptr<T> mySharedArray = std::make_unique<T[]>(16); 

dobry, wyjątek bezpieczne (i czystsze) alternatywą dla

std::shared_ptr<T> mysharedArray(new T[16], [](T* ptr){delete[] ptr;}); 

i jej pochodne, gdy nie mogę użyć Boost's shared array i chcę uniknąć dołączenia nagłówka vector lub array h mój kod?

+1

N.B. chociaż tablica ma zagwarantowane poprawne usunięcie, istnieje potencjalny problem z bezpieczeństwem podczas konwersji 'unique_ptr ' -> 'shared_ptr ' -> 'shared_ptr ', zobacz http://stackoverflow.com/q/32483375/981959 –

Odpowiedz

6

Tak, Twój przykład jest ważny z powodów, które podałeś. unique_ptr::pointer to int *, a próbujesz przekazać prawo własności do pliku shared_ptr<int>, więc konstruktor konwersji, który zaznaczysz, będzie uczestniczył w rozdzielczości przeciążania i utworzy kopię narzędzia (std::default_delete<int[]>), ponieważ nie jest to typ odniesienia.

Więc po to ważny i wezwie delete[] gdy liczba shared_ptr odniesienie idzie do zera

std::shared_ptr<T> mySharedArray = std::make_unique<T[]>(16); 

Innym sposobem, aby napisać to, inny niż lambda masz pokazane jest

std::shared_ptr<T> mySharedArray(new T[16], std::default_delete<int[]>()); 

, co spowoduje, że mySharedArray uzyska ten sam wskaźnik zużycia, co poprzednia linia.

Powiązane problemy