Boost Shared Array e Scoped Array (shared_array e scoped_array)

Para ver o artigo anterior da série: Boost Scoped Pointer

Todo os smart pointers que mostrei até agora tem um problema que ainda não vimos como resolver: eles não funcionam com arrays! Isso acontece pois como todo programador C++ sabe (sabe mesmo não é?) devemos usar o delete[] para liberar a memória de um array, por exemplo:


#include <string>
#include <iostream>

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

        ~Person()
        {
            using namespace std;

            cout << "Fui destruido: " << m_Name << endl;
        }

    private:
        std::string m_Name;
};

int main(int, char **)
{
    Person *p = new Person[10];

    delete []p;

    return(0);
}

Se ao invés do delete[], for usado um delete comum, geralmente a memória é liberada corretamente, mas somente o destrutor do primeiro elemento do array é executado. Isto ocorre porque o delete comum (e o compilador na maioria das vezes) não tem como saber se um ponteiro aponta para um elemento apenas ou para um array. Então precisamos de alguma forma avisar eles sobre o array. Para fazer o teste, coloque um printf no destrutor da classe Person e modifique o exemplo acima para rodar o delete normal.

Mas como o compilador sabe quantos elementos destruir? Isso depende, uma implementação que pode ser usada é toda vez que for alocado um array, alocar antes dele um int e colocar nele o tamanho do array, assim o delete poderia ser implementado +/- assim:


template <typename T>
operator delete[](T *ar)
{
    int num = ((int *)ar)-1;

    for(int i = 0;i < num; ++i)
        ar[i].~T();

    free(ar);
}

Alguns compiladores usam técnicas semelhantes a esta, mas não existe nenhuma garantia sobre qual a técnica a ser utilizada, isso depende da implementação. Agora porque não incluir em todos os ponteiros alocados um int com a quantidade de objetos? Bom, simplesmente porque senão toda a alocação teria esse ônus de um int a mais (acredito que devam existir outros problemas, mas isso não vem ao caso), que poderia atrapalhar a vida de alguns programas, dessa forma, seguindo a filosofia do C++ “Você não paga pelo o que não usa” temos como resultado dois operadores de delete.

Smart Pointers e Arrays

Para contornar esse problema das arrays, a boost criou então o shared_array, que é usado especificamente para arrays. Seu uso é quase o mesmo do shared_ptr:


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

int main(int, char **)
{
    const int NUM = 10;
    boost::shared_array<Person> p(new Person[NUM]);

    using namespace std;

    for(int i = 0;i < NUM; ++i)
        p[i].SetName(string("Bruno"));

    return(0);
}

Não tem segredo! Existe um outro smart pointer para arrays, o scoped_array, que tem comportamento idêntico ao scoped_ptr, mas pode ser usado com arrays:


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

int main(int, char **)
{
    const int NUM = 10;
    boost::scoped_array<Person> p(new Person[NUM]);

    using namespace std;
    for(int i = 0;i < NUM; ++i)
        p[i].SetName(string("bcs"));

    return(0);
}

Novamente não mudou nada no código, apenas o nome do smart pointer usado. Mas lembre-se que nos bastidores tivemos algumas mudanças, pois o shared_array precisa assim como o shared_ptr alocar um objeto para contagem de referencia, já o scoped_array (da mesma forma que o scoped_ptr) não precisa de nada disso.

No próximo post, vamos ver a ultima classe de smart pointer da Boost, o intrusive_ptr.

Próximo artigo da série: Boost Intrusive Pointer

Uma resposta para “Boost Shared Array e Scoped Array (shared_array e scoped_array)”

  1. Caloni.com.br » Blog Archive » Últimas pesquisas na blogosfera nacional Disse:

    [...] Boost Shared Array e Scoped Array [...]

Deixe uma resposta