Pergunta

boost::shared_ptr tem um construtor incomum

template<class Y> shared_ptr(shared_ptr<Y> const & r, T * p);

e eu sou um pouco perplexo quanto ao que isso seria útil para. Basicamente, ele compartilha a propriedade com r, mas .get() voltará p. não r.get()!

Isto significa que você pode fazer algo como isto:

int main() {
    boost::shared_ptr<int> x(new int);
    boost::shared_ptr<int> y(x, new int);

    std::cout << x.get() << std::endl;
    std::cout << y.get() << std::endl;

    std::cout << x.use_count() << std::endl;
    std::cout << y.use_count() << std::endl;
}

E você vai ter este:

0x8c66008
0x8c66030
2
2

Observe que os ponteiros são separados, mas ambos afirmam ter um use_count de 2 (uma vez que partilham a propriedade do mesmo objeto).

Assim, o int propriedade de x vai existir enquanto x ou y está ao redor. E se eu entender os docs corrigir, o segundo int nunca é destruída. Eu já confirmou isso com o seguinte programa de teste:

struct T {
    T() { std::cout << "T()" << std::endl; }
    ~T() { std::cout << "~T()" << std::endl; }
};

int main() {
    boost::shared_ptr<T> x(new T);
    boost::shared_ptr<T> y(x, new T);

    std::cout << x.get() << std::endl;
    std::cout << y.get() << std::endl;

    std::cout << x.use_count() << std::endl;
    std::cout << y.use_count() << std::endl;
}

Este saídas (como esperado):

T()
T()
0x96c2008
0x96c2030
2
2
~T()

Então ... qual é a utilidade dessa construção incomum que as ações de propriedade de um ponteiro, mas age como um outro ponteiro (que não possui), quando utilizado.

Foi útil?

Solução

Já é útil quando você quiser compartilhar um membro da classe e uma instância da classe é um shared_ptr, como o seguinte:

struct A
{
  int *B; // managed inside A
};

shared_ptr<A>   a( new A );
shared_ptr<int> b( a, a->B );

eles compartilham a contagem de uso e outras coisas. É otimização de uso de memória.

Outras dicas

Para expandir a de Leiz de Piotr respostas , esta descrição de shared_ptr<> ' aliasing' é de um papel WG21, "Melhorar shared_ptr para C ++ 0x, Revisão 2" :

III. Suporte Aliasing

Os usuários avançados muitas vezes exigem o capacidade de criar um shared_ptr instância p que as ações propriedade com outro (mestre) shared_ptr q mas aponta para um objecto que não é uma base de de *q. *p pode ser um membro ou um elemento de *q, por exemplo. este seção propõe um adicional construtor que pode ser utilizado para este propósito.

Um efeito colateral interessante deste aumento do poder expressivo é que agora as funções *_pointer_cast pode ser implementado no código do usuário. o função make_shared fábrica apresentado mais adiante neste documento também pode ser implementado utilizando apenas o público a interface de shared_ptr através do aliasing construtor.

Impacto:

Este recurso estende a interface de shared_ptr em um compatível com versões anteriores forma que aumenta a sua expressiva energia e é, portanto, fortemente recomendado para ser adicionado à ++ 0x C padrão. Ele apresenta nenhuma fonte-e problemas de compatibilidade binária.

Texto:

Adicionar a shared_ptr [Util.smartptr.shared] o seguinte construtor:

template<class Y> shared_ptr( shared_ptr<Y> const & r, T * p );

Adicione o seguinte ao [Util.smartptr.shared.const]:

template<class Y> shared_ptr( shared_ptr<Y> const & r, T * p );

Efeitos:. Constrói uma instância shared_ptr que armazena p e ações propriedade com r

Pós-condições:. get() == p && use_count() == r.use_count()

Lança:. nada

[Nota: Para evitar a possibilidade de um apontador pendente, o usuário desse construtor deve garantir que p permanece válido, pelo menos, até que o grupo de proprietários de r é destruído. -. Nota final]

[Nota: Este construtor permite a criação de um vazio shared_ptr exemplo, com um ponteiro não nulo armazenado. -. Nota final]

Você também pode usar isso para manter ponteiros fundidas dinâmicos, ou seja:.

class A {};
class B: public A {};

shared_ptr<A> a(new B);
shared_ptr<B> b(a, dynamic_cast<B*>(a.get()));

Você pode ter um ponteiro para algum motorista ou estrutura de dados de uma API de nível inferior que podem alocar dados adicionais pelo seu api nível inferior ou outros meios. Neste caso, pode ser interessante para aumentar a use_count mas retornar os dados adicionais se o primeiro ponteiro detém os outros ponteiros de dados.

Eu coloquei construtor aliasing de shared_ptr em uso na minha pequena biblioteca:

http://code.google.com/p/infectorpp/ (apenas a minha simples recipiente COI)

A questão é que desde que eu precisava de um shared_ptr do tipo conhecido por ser retornado de uma classe polimórfica (que não sabe o tipo). Eu não era capaz de converter implicitamente o shared_ptr com o tipo que eu precisava.

No arquivo " InfectorHelpers.hpp "(linha 72-99) você pode ver que em ação para o tipo IAnyShared.

Aliasing construtor cria shared_ptr que não exclui os ponteiros eles estão realmente apontando para, mas ainda aumentar o contador de referência para o objeto original e que pode ser extremamente útil.

Basicamente, você pode criar um ponteiro para qualquer coisa usando construtor aliasing e ameaça-lo como um contador de referência.

//my class
std::shared_ptr<T> ist;
int a; //dummy variable. I need its adress

virtual std::shared_ptr<int> getReferenceCounter(){
    return std::shared_ptr<int>(ist,&a); //not intended for dereferencing
}

virtual void* getPtr(); //return raw pointer to T

Agora temos tanto "um contador de referência" e um ponteiro para uma istance de T, dados suficientes para criar algo com o aliasing construtor

std::shared_ptr<T> aPtr( any->getReferenceCounter(), //share same ref counter 
               static_cast<T*>(any->getPtr()) ); //potentially unsafe cast!

Eu não pretendo ter inventado esse uso para o construtor aliasing, mas eu nunca vi alguém fazer o mesmo. Se você está supondo que, se esse código sujo funciona a resposta é sim.

Para "shared_ptr<B> b(a, dynamic_cast<B*>(a.get()));"

Eu acho que não é a maneira recomendada usando ponteiro inteligente.

A maneira recomendada de fazer esta conversão tipo deve ser:

shared_ptr<B> b(a);

Uma vez que no documento impulso é mencionado que:

shared_ptr<T> pode ser implicitamente convertido para shared_ptr<U> sempre que T * pode ser implicitamente convertido para U *. No em particular, é shared_ptr<T> implicitamente conversível para shared_ptr<T> const, para shared_ptr<U> onde U é uma base de acessível de T, e a shared_ptr<void>.

Além disso, também temos dynamic_pointer_cast que poderia fazer diretamente a conversão em objeto ponteiro inteligente e ambos destes dois métodos seria muito mais seguro do que a maneira ponteiro bruto lançando manualmente.

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