O que é shared_ptr de impulso (shared_ptr const & R, T * p) utilizado?
-
05-07-2019 - |
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.
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ânciap
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çãomake_shared
fábrica apresentado mais adiante neste documento também pode ser implementado utilizando apenas o público a interface deshared_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 armazenap
e ações propriedade comr
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 der
é 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 parashared_ptr<U>
sempre que T * pode ser implicitamente convertido para U *. No em particular, éshared_ptr<T>
implicitamente conversível parashared_ptr<T> const
, parashared_ptr<U>
onde U é uma base de acessível de T, e ashared_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.