smart - weak_ptr example c++
shared_ptr para uma matriz: deve ser usado? (2)
Com o C ++ 17 , o shared_ptr
pode ser usado para gerenciar uma matriz alocada dinamicamente. O argumento do modelo shared_ptr
neste caso deve ser T[N]
ou T[]
. Então você pode escrever
shared_ptr<int[]> sp(new int[10]);
De n4659, [util.smartptr.shared.const]
template<class Y> explicit shared_ptr(Y* p);
Requer:
Y
será um tipo completo. A expressãodelete[] p
, quandoT
é um tipo de array, oudelete p
, quandoT
não é um tipo de array, deve ter um comportamento bem definido, e não deve lançar exceções.
...
Comentários: QuandoT
é um tipo de matriz, este construtor não deve participar na resolução de sobrecarga a menos que a expressãodelete[] p
seja bem formada eT
sejaU[N]
eY(*)[N]
seja convertível emT*
, ouT
éU[]
eY(*)[]
é convertível emT*
. ...
Para suportar isso, o tipo de membro element_type
agora é definido como
using element_type = remove_extent_t<T>;
Elementos de matriz podem ser acessados usando operator[]
element_type& operator[](ptrdiff_t i) const;
Requer:
get() != 0 && i >= 0
. SeT
éU[N]
,i < N
. ...
Comentários: QuandoT
não é um tipo de matriz, não é especificado se essa função de membro é declarada. Se for declarado, não é especificado qual é o seu tipo de retorno, exceto que a declaração (embora não necessariamente a definição) da função deve ser bem formada.
Antes do C ++ 17 , o shared_ptr
não podia ser usado para gerenciar matrizes alocadas dinamicamente. Por padrão, shared_ptr
chamará delete
no objeto gerenciado quando não houver mais referências a ele. No entanto, quando você aloca usando new[]
você precisa chamar delete[]
, e não delete
, para liberar o recurso.
Para usar corretamente o shared_ptr
com um array, você deve fornecer um deleter personalizado.
template< typename T >
struct array_deleter
{
void operator ()( T const * p)
{
delete[] p;
}
};
Crie o shared_ptr da seguinte maneira:
std::shared_ptr<int> sp(new int[10], array_deleter<int>());
Agora shared_ptr
irá chamar corretamente delete[]
ao destruir o objeto gerenciado.
O apagador personalizado acima pode ser substituído por
a especialização parcial
std::default_delete
para tipos de matrizstd::shared_ptr<int> sp(new int[10], std::default_delete<int[]>());
uma expressão lambda
std::shared_ptr<int> sp(new int[10], [](int *p) { delete[] p; });
Além disso, a menos que você realmente precise compartilhar o poder de propriedade do objeto gerenciado, um unique_ptr
é mais adequado para essa tarefa, pois possui uma especialização parcial para os tipos de matriz.
std::unique_ptr<int[]> up(new int[10]); // this will correctly call delete[]
Alterações introduzidas pelas Extensões C ++ para Fundamentos da Biblioteca
Outra alternativa pré-C ++ 17 às listadas acima foi fornecida pela Especificação Técnica de Fundamentos da Biblioteca , que aumentou shared_ptr
para permitir que funcione fora da caixa para os casos em que possui uma matriz de objetos. O rascunho atual das mudanças shared_ptr
programadas para este TS pode ser encontrado em N4082 . Essas alterações serão acessíveis através do namespace std::experimental
e incluídas no cabeçalho <experimental/memory>
. Algumas das alterações relevantes para suportar shared_ptr
para matrizes são:
- A definição do tipo de membro element_type
changes
typedef T element_type;typedef typename remove_extent<T>::type element_type;
- O operator[]
membro operator[]
está sendo adicionado
element_type& operator[](ptrdiff_t i) const noexcept;
- Ao contrário da especialização parcial unique_ptr
para matrizes, shared_ptr<T[]>
e shared_ptr<T[N]>
serão válidos e ambos resultarão em delete[]
sendo chamado na matriz gerenciada de objetos.
template<class Y> explicit shared_ptr(Y* p);
Requer :
Y
será um tipo completo. A expressãodelete[] p
, quandoT
é um tipo de matriz, oudelete p
, quandoT
não é um tipo de array, deve ser bem formada, deve ter um comportamento bem definido e não deve lançar exceções. QuandoT
éU[N]
,Y(*)[N]
deve ser convertível emT*
; quandoT
éU[]
,Y(*)[]
deve ser convertível emT*
; caso contrário,Y*
será convertível emT*
.
Apenas uma pequena consulta sobre shared_ptr
.
É uma boa prática usar shared_ptr
apontando para uma matriz? Por exemplo,
shared_ptr<int> sp(new int[10]);
Se não, então por que não? Uma razão pela qual eu já estou ciente é que não é possível incrementar / decrementar o shared_ptr
. Por isso, não pode ser usado como um ponteiro normal para um array.
Uma alternativa possivelmente mais fácil que você pode usar é shared_ptr<vector<int>>
.