Desanexar um ponteiro de um shared_ptr? [duplicado]
-
11-09-2019 - |
Pergunta
Duplicate possíveis:
Como liberar ponteiro de boost :: shared_ptr?
A função da minha interface retorna um ponteiro para um objeto. O usuário deve tomar posse desse objeto. Eu não quero voltar a Boost.shared_ptr, porque eu não quero forçar os clientes a usar impulso. Internamente no entanto, eu gostaria de armazenar o ponteiro em um shared_ptr para evitar vazamentos de memória em caso de exceções etc. Não parece haver nenhuma maneira de separar um ponteiro de um ponteiro compartilhado. Todas as ideias aqui?
Solução
O que você está procurando é uma função release
; não shared_ptr
não tem uma função de liberação. Per o impulso manual :
Q. Por que não shared_ptr fornecer uma função de desbloqueio ()?
A. shared_ptr não pode dar posse a menos que seja única () porque a outra cópia ainda vai destruir o objeto.
Considere o seguinte:
shared_ptr<int> a(new int);
shared_ptr<int> b(a); // a.use_count() == b.use_count() == 2
int * p = a.release();
// Who owns p now? b will still call delete on it in its destructor.
Além disso, o ponteiro retornado por release () seria difícil para desalocar confiável, como o shared_ptr fonte poderia ter sido criado com um deleter personalizado.
Duas opções que você pode considerar:
- Você pode usar
std::tr1::shared_ptr
, o que exigiria que os usuários usam uma implementação C ++ biblioteca de suporte TR1 ou para impulsionar o uso; pelo menos isso iria dar-lhes a opção entre os dois. - Você poderia implementar sua própria
boost::shared_ptr
-como ponteiro e uso compartilhado de que em suas interfaces externas.
Você também pode olhar para a discussão neste pergunta sobre usando boost :: shared_ptr na interface de uma biblioteca público.
Outras dicas
sempre há uma maneira: -)
Há de fato uma razão para que eles não fornecem um método release (), mas não é impossível criar um. Faça o seu próprio deleter. Algo na linha de (realmente não tenho compilado o código, mas esta é a noção geral):
template <typename T>
class release_deleter{
public:
release_deleter() : released_(new some_atomic_bool(false)){}
void release() {released_->set(true);}
void operator()(T* ptr){if(!released_->get()) delete ptr;}
private:
shared_ptr<some_atomic_bool> released_;
}
..
shared_ptr<some_type> ptr(new some_type, release_deleter<some_type>());
..
release_deleter<some_type>* deleter = get_deleter<release_deleter<some_type>>(ptr);
deleter->release();
some_type* released_ptr = ptr.get();
O usuário deve tomar posse desse objeto. Eu não quero voltar a Boost.shared_ptr,
shared_ptr
expressa compartilhada propriedade, e você quer que sua interface para expressar transferência de propriedade. std::auto_ptr
seria, assim, mais aplicável aqui.
Internamente no entanto, eu gostaria de armazenar o ponteiro em um shared_ptr para evitar vazamentos de memória em caso de exceções
Mais uma vez, shared_ptr
pode não ser a melhor ferramenta para esse trabalho. Para evitar fugas no caso de exceções, scoped_ptr
ou auto_ptr
seria mais adequado.
Use um shared_ptr
a um scoped_ptr
ao recurso (shared_ptr<scoped_ptr<Resource>>
). Dessa forma, você começa a contagem de referência do shared_ptr
, que irá destruir automaticamente o recurso se e somente se ele ainda está ligado à scoped_ptr
. Mas você pode destacar o scoped_ptr
Quando estiver pronto para a mão off propriedade.
Como James foi bem coberto você realmente não pode desanexar um ponteiro compartilhado.
Você precisa de vários proprietários internamente, ou você está transferindo a propriedade de sua classe para o cliente? Nesse caso, uma std::auto_ptr
pode caber a conta.
Se você está preocupado com a semântica surpreendentes de std::auto_ptr
, você poderia prendê-lo internamente pelo boost::scoped_ptr
, e retirá-la no ponto em que entregá-lo - deixando para o cliente manualmente excluí-lo ou armazená-lo em seu próprio ponteiro inteligente.
Se você tem vários proprietários do seu lado, você poderia usar uma contagem intrusiva. Internamente você pode então usar boost::intrusive__ptr
, mas mão do ponteiro bruto na interface. O cliente pode então trabalhar manualmente com contagem de referência, ou armazená-lo em um boost::intrusive_ptr
-se (mas você não torná-los dependem dele)