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?

Foi útil?

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)

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top