Pergunta

Eu escrevi uma biblioteca que expõe as referências a vários tipos de objetos relacionados. Todos esses objetos têm suas vidas gerido pela biblioteca internamente através boost::shared_ptr

Um usuário da biblioteca também seria capaz de saber, pela natureza da biblioteca, as vidas de qualquer um dos objetos expostos. Então eles poderiam armazenar ponteiros ou manter referências a esses objetos. Seria razoável para eles fazer isso e saber quando esses objetos não são mais válidas.

Mas eu me sinto culpado forçando meus usuários para ser razoável.

É aceitável ter uma biblioteca expor weak_ptr de que seus objetos? Já outras bibliotecas feito isso?

Eu tenho perfilado uso deste biblioteca em aplicativos e descobriram que ele seja muito missão crítica para expor weak_ptr exclusivamente.

seria mais sensato para ter funções de correspondência API expor tanto uma referência ou a weak_ptr ou fazer qualquer objeto capaz de expor um weak_ptr para si?

Foi útil?

Solução

Se os smart_ptrs já estão directamente acessíveis aos usuários da biblioteca, então eles já tenho acesso aos weak_ptrs, simplesmente através do construtor do weak_ptr correspondente. Mas se os smart_ptrs são todos internos para a biblioteca, que é uma história diferente.

Nesse caso, eu recomendo deixar cada objeto desmaiar weak_ptrs a si mesmo, para além de qualquer outro acesso suas ofertas da biblioteca. Isso dá aos usuários mais flexibilidade: se eles precisam de um weak_ptr, eles têm acesso imediato a ele; Se eles precisam de um shared_ptr, eles podem facilmente obtê-lo; e se eles só precisam de acesso ao objeto em si, eles podem ignorar os ponteiros inteligentes inteiramente.

É claro, eu não sei o que sua biblioteca faz ou como ele é usado ou projetado. Isso poderia mudar a minha recomendação.

Outras dicas

Chegando-se com mecanismos complicadas para chegar aos objetos de sua biblioteca só vai resultar em pessoas que não utilizam sua biblioteca. Se a semântica do ditame biblioteca você precisa ter pessoas que usam weak_ptrs, não há maneira de contornar o usuário saber que os objetos podem desaparecer em algum ponto. Faça o expresso interface de tanta informação sobre o uso da biblioteca possível, mantém documentação para baixo e torna infinitamente mais fácil de usar.

Você não pode projetar em torno de bad / usuários inexperientes.

Se você dá a seus clientes acesso a weak_ptrs eles podem apenas bloqueá-los para criar shared_ptrs e acabam atrasando a destruição de objetos. Que podem causar problemas com a sua biblioteca.

Eu sugiro que envolve um weak_ptr em alguma outra classe e dando o chamador um shared_ptr a isso. Dessa forma, eles não podem apenas chamar weak_ptr<T>::lock(). Você parece ter restrições de desempenho que podem influenciar como você implementá-lo, mas um shared_ptr<InterfaceClass> pode ser um bom caminho a percorrer, e manter a classe com o weak_ptr interna à sua biblioteca.

Dessa forma, você também manter estes detalhes de implementação fora de sua biblioteca de interface e você pode mudar a maneira de implementá-lo sem alterar a sua interface.

Eu não vejo qualquer problema com weak_ptrs expondo, especialmente dado que TR1 tem ponteiros inteligentes semelhantes (PDF).

TR1 é amplamente implementado pelo Visual Studio e GCC, mas não alguns dos outros compiladores lá fora. Mas quando ele é implementado em todos os compiladores que lhe interessa, você pode querer refazer a API para expor esses ponteiros inteligentes em seu lugar.

Se você quer tanto armadilha uso inválido da biblioteca (tentando acessar os objetos quando eles foram apagados), bem como ter um API de alto desempenho (nenhum de weak_ptr e shared_ptr de na API), então você poderia considerar ter uma API diferente para depurar e nondebug constrói.

Vamos supor, por simplicidade que você tem apenas uma classe de objetos que expõem; chamar este objeto de classe. O tipo de ponteiro que você voltar da API para acessar os objetos internos é, então, definido como:

#ifdef DEBUG
typedef ObjectPtrFacade ObjectPtr 
#else
typedef Object * ObjectPtr;
#endif

Aqui, a fachada é classe que você escreve. Ele funciona mais ou menos assim:

class ObjectPtrFacade {
public:
    ObjectPtrFacade(Object *o) : wptr(o) { }
    // copy constructor and assignment here etc. (not written)
    Object * operator -> () const { return access(); }
    Object & operator * () const { return *access(); }
private:
    Object * access() { 
      assert(wptr.use_count() > 0);
      return (Object *)(wptr.lock());
    }
    weak_ptr<Object> wptr; 
}

Desta forma, sempre que você construir uma compilação de depuração, você tem um tipo especial de ponteiro inteligente em uso que afirma antes de acessar o objeto que sua use_count () é maior do que zero, ou seja, que o objeto ainda existe. Se o objeto foi lançado, você recebe um assert falhando, que é melhor do que uma referência ponteiro nulo.

Em geral, é claro que é assim que o uso weak_ptr de não ajuda se você tiver usuários "estúpido" da API, porque eles poderiam chamá-lock () e depois ainda fazer uma referência nula-ponteiro após as weak_ptr retorna um shared_ptr que está vazia ...

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