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ão delete[] p , quando T é um tipo de array, ou delete p , quando T não é um tipo de array, deve ter um comportamento bem definido, e não deve lançar exceções.
...
Comentários: Quando T é um tipo de matriz, este construtor não deve participar na resolução de sobrecarga a menos que a expressão delete[] p seja bem formada e T seja U[N] e Y(*)[N] seja convertível em T* , ou T é U[] e Y(*)[] é convertível em T* . ...

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 . Se T é U[N] , i < N . ...
Comentários: Quando T 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 matriz

    std::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ão delete[] p , quando T é um tipo de matriz, ou delete p , quando T não é um tipo de array, deve ser bem formada, deve ter um comportamento bem definido e não deve lançar exceções. Quando T é U[N] , Y(*)[N] deve ser convertível em T* ; quando T é U[] , Y(*)[] deve ser convertível em T* ; caso contrário, Y* será convertível em T* .

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>> .







shared-ptr