Pergunta

Em um projeto de C ++ que usa ponteiros inteligentes, tais como boost::shared_ptr, o que é uma filosofia de bom design de utilização do " this "?

Considere que:

  • É perigoso para armazenar o ponteiro bruto contido em qualquer ponteiro inteligente para uso posterior. Você deu-se o controle de exclusão de objeto e confiar o ponteiro inteligente de fazê-lo no momento certo.

  • membros da classe não-estáticos intrinsecamente usar um this ponteiro. É um ponteiro não processado e que não pode ser alterado.

Se eu armazenar this em outra variável ou passá-lo para outra função que poderia guardá-la para mais tarde ou vinculá-lo em uma chamada de retorno, eu estou criando erros que são introduzidos quando alguém decide fazer um ponteiro compartilhado para minha classe .

Tendo em conta que, quando é que nunca apropriado para mim explicitamente usar um ponteiro this? Existem paradigmas de projeto que podem prevenir bugs relacionados a isso?

Foi útil?

Solução

Enquanto eu não tenho uma resposta geral ou algum idioma, não é boost::enable_shared_from_this . Ele permite que você para obter um shared_ptr gerenciar um objeto que já é gerido por shared_ptr. Uma vez que em uma função membro você não tem nenhuma referência àqueles de shared_ptr gestão, enable_shared_ptr lhe permite obter uma instância shared_ptr e aconteceu que quando você precisa passar a este ponteiro.

Mas isso não vai resolver o problema de passar this a partir do construtor, uma vez que, nesse momento, não shared_ptr está a gerir o seu objeto ainda.

Outras dicas

Pergunta errada

Em um C ++ projeto que usa ponteiros inteligentes

A questão não tem nada a ver com ponteiros inteligentes, na verdade. É apenas cerca de propriedade.

Ponteiros inteligentes são apenas ferramentas

Eles mudam nada WRT o conceito de propriedade, esp. a necessidade de ter a propriedade bem definidos em seu programa , o fato de que a propriedade pode ser voluntariamente transferido, mas não pode ser tomada por um cliente.

Você deve entender que os ponteiros inteligentes (também bloqueia e outros objetos RAII) representam um valor e uma relação WRT este valor, ao mesmo tempo. A shared_ptr é uma referência a um objeto e estabelece uma relação: o objeto não deve ser destruído antes que este shared_ptr, e quando isso shared_ptr é destruído, se ele é o último aliasing este objeto, o objeto deve ser destruído imediatamente. (unique_ptr pode ser visto como um caso especial de shared_ptr onde não é zero aliasing por definição, de modo que o unique_ptr é sempre o último aliasing um objeto.)

Por que você deve usar ponteiros inteligentes

É recomendado usar ponteiros inteligentes porque expressam um monte com apenas variáveis ??e funções declarações.

Ponteiros inteligentes só pode expressar um projeto bem definido, eles não tiram a necessidade de definir propriedade. Em contraste, a coleta de lixo tira a necessidade de definir quem é responsável pela desalocação de memória. (Mas não tira a necessidade de definir quem é responsável por outros recursos de limpeza.)

Mesmo em linguagens de lixo não puramente funcional coletadas, você precisa fazer a posse clara: você não deseja substituir o valor de um objeto se outros componentes ainda precisa o valor antigo. Isto é especialmente verdadeiro em Java, onde o conceito de propriedade de estrutura de dados mutáveis ??é extremamente importante em programas de rosca.

E sobre ponteiros crus?

O uso de um ponteiro não processado não significa que não há nenhuma propriedade. Ele só não é descrito por uma declaração de variável. Pode ser descrito em comentários, em seus documentos de design, etc.

É por isso que muitos programadores C ++ considerar que o uso de ponteiros crus em vez do ponteiro inteligente adequada é inferior : porque é menos expressiva (evitei os termos "bom" e "ruim" de propósito). Eu acredito que o kernel do Linux seria mais legível com alguns C ++ objetos para expressar relações.

Você pode implementar um projeto específico, com ou sem ponteiros inteligentes. A implementação que usos ponteiro inteligente apropriadamente será considerada superior por muitos programadores C ++.

A sua verdadeira questão

Em um projeto C ++, o que é uma filosofia de bom design de utilização do "isto"?

Isso é muito vago.

É perigoso para armazenar o ponteiro bruto para uso posterior.

Por que você precisa para um ponteiro para uso posterior?

Você deu-se o controle de exclusão de objeto e confiar em que o componente responsável para fazê-lo no momento certo.

De fato, algum componente é responsável por toda a vida útil da variável. Você não pode assumir a responsabilidade:. Tem que ser transferido

Se eu armazenar esta em outra variável ou passá-lo para outra função que poderia guardá-la para mais tarde ou vinculá-lo em uma chamada de retorno, eu estou criando erros que são introduzidos quando alguém decide usar minha classe.

Obviamente, uma vez que o chamador não é informado que a função irá esconder um ponteiro e usá-lo posteriormente sem o controle do chamador, você está criando bugs.

A solução é, obviamente, quer:

  • responsabilidade transferência para lidar com a vida útil do objeto para a função
  • assegurar que o ponteiro só é guardada e utilizada sob o controlo do chamador

Somente no fcaso irst, você pode acabar com um ponteiro inteligente na implementação de classe.

A origem do problema

Eu acho que o problema é que você está se esforçando para assuntos complicar usando ponteiros inteligentes. Ponteiros inteligentes são ferramentas para tornar as coisas mais fáceis, não mais. Se ponteiros inteligentes complicar a sua especificação, em seguida, repensar a sua especificação em termos de coisas mais simples.

Não tente introduzir ponteiros inteligentes como uma solução antes de você ter um problema.

Apenas introduzir ponteiros inteligentes para resolver um problema bem definido específico. Porque você não descrever um problema bem definido específico, não é possível discutir uma solução específica (envolvendo ponteiros inteligentes ou não).

Um exemplo de uso correto é return *this; em funções como operador ++ () e operador << ().

Quando você estiver usando uma classe ponteiro inteligente, você está certo de que é perigoso para expor diretamente "this". Existem algumas classes ponteiro relacionadas com boost::shared_ptr<T> que podem ser de uso:

  • boost::enable_shared_from_this<T>
    • Oferece a capacidade de ter um objeto retornar um ponteiro compartilhado para si que utiliza os mesmos dados de contagem de referência como um ponteiro compartilhada existente para o objeto
  • boost::weak_ptr<T>
    • trabalha lado a lado com ponteiros compartilhados, mas não manter uma referência para o objeto. Se todos os ponteiros do compartilhados ir embora e o objeto é liberado, um ponteiro fraco vai ser capaz de dizer que o objeto não existe mais e irá voltar NULL em vez de um ponteiro para a memória inválido. Você pode usar ponteiros fracos para obter ponteiros compartilhados para um objeto contado referência válido.

Nenhum destes é infalível, é claro, mas eles vão, pelo menos, tornar o código mais estável e seguro, proporcionando um acesso adequado e contagem de referência para os seus objetos.

Se você precisa usar this, apenas usá-lo explicitamente. ponteiros inteligentes envolver apenas os ponteiros dos objetos que eles próprios - seja EXCLUSIVAMENTE (unique_ptr) ou de forma compartilhada (shared_ptr).

Eu pessoalmente gosto de usar o este ponteiro ao acessar variáveis ??de membro da classe. Por exemplo:

void foo::bar ()
{
    this->some_var += 7;
}

É apenas uma questão inofensiva de estilo. Algumas pessoas gostam, somepeople não.

Mas usando o este ponteiro para qualquer outra coisa é provável que causar problemas. Se você realmente precisa fazer fantasia coisas com ele, você realmente deve reconsiderar o seu design. Uma vez vi um código que, no construtor de uma classe, é atribuído a este ponteiro para outro ponteiro armazenado em outro lugar! Isso é uma loucura, e eu não pode nunca pensar em uma razão para fazer isso. O código inteiro era uma grande confusão, pelo caminho.

Você pode nos dizer o que exatamente você quer fazer com o ponteiro?

Outra opção é usar ponteiros inteligentes intrusivos, e cuidar de contagem de referência dentro do objeto em si, não os ponteiros. Isso requer um pouco mais de trabalho, mas é realmente mais eficiente e fácil de controlar.

Outra razão para passar ao redor isso é se você quiser manter um registro central de todos os objetos. No construtor, um objeto chama um método estático do registro com isso. É útil para vários publish / subscribe mecanismos, ou quando você não quer que o registro para conhecimento necessidade de que objetos / classes estão no sistema.

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