Ponto V!

Home C/C++ Smart Pointers Boost Intrusive Pointer (intrusive_ptr)
Bruno Crivelari Sanches
Boost Intrusive Pointer (intrusive_ptr)Imprimir
Escrito por Bruno Crivelari Sanches

Para ver o tutorial anterior da série: Boost Shared Array e Scoped Array

Finalmente chegamos na ultima classe de smart pointer da Boost. O intrusive_ptr é semelhante ao shared_ptr, mas a diferença é que ao invés de alocar um objeto para controlar as referências, ele usa o próprio objeto que ele armazena para esse fim.

Dessa forma, o objeto apontado por ele precisa prover métodos ou funções que cuidem da contagem de referência, por isso o nome de intrusive (ou intruso), porque é necessário modificar o objeto que ele vai armazenar para que se possa usa-lo com o intrusive_ptr, devido a essa forma de implementação, já notamos aqui que não podemos usar o intrusive_ptr com qualquer tipo de objeto como fazíamos com o shared_ptr.

Quando um intrusive_ptr precisa incrementar as referências, ele chama a função intrusive_ptr_add_ref (passando como parâmetro o ponteiro do objeto). No processo inverso, quando é preciso decrementar uma referência, ele invoca a função intrusive_ptr_release, que fica responsável por decrementar as referências e destruir o objeto quando o contador chega a zero.

Vamos então modificar a classe Person para que ela possa ser usada com o intrusive_ptr:

#include <boost/intrusive_ptr.hpp>
#include <string>

class Person
{
    public:
        inline Person(): m_RefCount(0) { }
        inline Person(const Person &p): 
            m_Name(p.m_Name),
            m_RefCount(0)
        {
        }

        inline const Person &operator=(const Person &p)
        {
            m_Name = p.m_Name;
            return(*this);
        }

        inline void SetName(const std::string &name)
        {
            m_Name = name;
        }

    private:
        inline void AddRef()
        {
            ++m_RefCount;
        }

        inline void DecRef()
        {
            assert(m_RefCount > 0);
            --m_RefCount;
            if(m_RefCount == 0)
                delete this;
        }

        std::string m_Name;
        unsigned int m_RefCount;

        friend inline void intrusive_ptr_add_ref(Person *p);
        friend inline void intrusive_ptr_release(Person *p);
};

inline void intrusive_ptr_add_ref(Person *p)
{
    p->AddRef();
}

inline void intrusive_ptr_release(Person *p)
{
    p->DecRef();
}

int main(int argc, char **argv)
{
    using namespace boost;
    intrusive_ptr p(new Person());

    p->SetName("BCS");

    return(0);
}

A classe Person engordou um bocado agora, então vamos por partes:

  1. Foi adicionado o atributo m_RefCount que usamos como contador de referência, usamos um unsigned porque não tem o menor sentido um objeto com contagem negativa.
  2. Tive que adicionar um construtor para inicializar o contador com zero.
  3. Foi preciso também adicionar um construtor de cópia e um operador de atribuição para que o contador seja inicializado e copiado corretamente. Note que no operador de cópia, simplesmente não alteramos o contador.
  4. Criamos os métodos AddRef e DecRef, que incrementam e decrementam o contador, respectivamente. O DecRef possui um assert apenas para tentarmos pegar algum estado inconsistente. Note que o objeto é suicida, se o contador chegou a zero, ele se mata (delete this).
  5. Declaramos as funções intrusive_ptr_add_ref e intrusive_ptr_release para a classe Person, note que elas simplesmente invocam os AddRef e o DecRef. Outro detalhe foi a declaração delas como friend da classe Person, desse modo podemos deixar o acesso ao contador de referências privado e evitar uso equivocado desses métodos.

Vantagens

A primeira vista o intrusive_ptr parece ser uma versão mala do shared_ptr, mas existem muitos casos onde temos um grande numero de objetos e não podemos arcar com o peso de ter uma alocação extra para controle de referencias, nessas horas o intrusive_ptr se torna bem atraente.

Outra vantagem do intrusive_ptr é que podemos usar ele com objetos que já possuem algum controle por contagem de referencia, como por exemplo objetos COM do Windows, podemos simplesmente criar as funções intrusive_ptr_add_ref e intrusive_ptr_release adequadas.

Desvantagens

A maior desvantagem que vejo é que não existe uma implementação do weak_ptr, então é necessário tomar certo cuidado com referências circulares.

Outra desvantagem (que na verdade incomoda apenas quando vamos usa-lo pela primeira vez) é que ele se torna mais trabalhoso que o shared_ptr devido ao código extra para controle de referencias, mas novamente, isso acaba se pagando com as vantagens que temos.


Comentários (6)
  • Neto  - Não vejo ganho
    avatar

    Não vi ganhos se comparado ao Shared_ptr, pois cada instância do ponteiro conteria o contador de referencia. Agora, se o contador fosse static aí a coisa muda de figura. Concordam ?

  • Vinícius Godoy de Mendonça
    avatar

    A diferença é que o shared_ptr acaba com 2 variáveis.
    1. O contador de referência;
    2. A referência em si (um ponteiro, para o objeto que ele está apontando).

    O intrusive_ptr elimina a segunda, ao usar o próprio objeto.

    Não faz sentido o contador ser estático, pois ele deve contar quantas referências são feitas aquele objeto, não àquela classe.

  • Neto  - Hum
    avatar

    Entendo.... :lol:

  • Bruno Crivelari Sanches
    avatar

    O Interessante é que existe uma forma de usar o shared_ptr, onde ao se alocar o objeto, se aloca o contador no mesmo segmento de memória, antes ou depois do objeto em si, assim, ambos ficam no mesmo bloco e não se tem o custo da alocação extra.

    Só não sei como ele se comporta quando entra o weak_ptr, que faz falta quando só se usa o intrusive.

    T+

  • Neto
    avatar

    Hum.... Ja testou isso ?

  • Bruno Crivelari Sanches
    avatar

    Não, só vi exemplos a um bom tempo atrás.

    T+

Escrever um comentário
Your Contact Details:
Gravatar enabled
Comentário:
[b] [i] [u] [url] [quote] [code] [img]   
:angry::0:confused::cheer:B):evil::silly::dry::lol::kiss::D:pinch::(:shock:
:X:side::):P:unsure::woohoo::huh::whistle:;):S:!::?::idea::arrow:
Security
Por favor coloque o código anti-spam que você lê na imagem.
LAST_UPDATED2  

Busca

Linguagens

Twitter