[LHC] [GaroaHC] Re: Ainda sobre memória do Arduino, evitando o "new"

Leandro A. F. Pereira leandro at tia.mat.br
Tue Feb 23 18:27:16 PST 2016


2016-02-23 22:38 GMT-03:00 Alejandro Mesias <ale.mesias at gmail.com>:

> Agora só fica a dúvida como usar classe que extendem de.
>
> class A {}
> class B : public B {}
>
> A ob_a = new B;
>
> Como ficaria isso no auto, sem new?
>

Acho que tem algumas coisas que não ficaram claras.

O std::make_unique<T>() é apenas um "açúcar sintático" (implementado dentro
da biblioteca padrão do C++, não na linguagem em si), mas o que ele é, é
basicamente esse código abaixo. Desconsidere aí os parâmetros que serão
passados pro construtor, pois aí a coisa complica se quiser fazer algo
genérico:

    template <class T>
    std::unique_ptr<T> make_unique() {
        return std::unique_ptr<T>(new T);
    }

Então, sim, tem um new na jogada. E tem um delete também, dentro do
std::unique_ptr (é similar àquela classe File que coloquei no outro email).

O auto facilita a declaração de uma variável dentro dum bloco de comandos
por fazer a inferência do tipo. Escrever:

   auto foo = std::make_unique<Foo>();

É a mesma coisa que:

   std::unique_ptr<Foo> foo = std::make_unique<Foo>();

Que acaba sendo a mesma coisa que:

   std::unique_ptr<Foo> foo = std::unique_ptr<Foo>(new Foo);

Isso foi fácil fazer na linguagem, considerando que o compilador usava a
informação de tipo pra berrar na cara do usuário se estivesse atribuindo
pra um tipo errado pra, ao invés disso, declarar uma variável daquele tipo.

Agora à dúvida da classe herdada: não tem como fazer o que você quer; pelo
menos não do jeito que escreveu.

Pra entender o motivo, tem que lembrar do fato que uma struct e uma classe
em C++ são a mesma coisa. A única coisa que muda é a visibilidade padrão
dos elementos -- numa struct, são todos public por padrão, numa classe são
todos private por padrão. Structs inclusive podem ter métodos, virtuais ou
não, herdar, etc.

E, quando uma classe herda de outra, acontece basicamente isso o seguinte.
Vamos pra C agora, pra deixar a coisa mais fundamental:

    struct A {
       int foo;
    };

    struct B {
       struct A super;
       int bar;
    };

As coisas complicam um pouco mais por causa de métodos virtuais herança
múltipla, é claro, mas o ponto é, fazer isso não vai rolar:

    struct B acme;
    struct A meep = acme;

Pois A e B são de tipos diferentes.

Entretanto, "super" na struct B é o primeiro elemento e ele tá todo lá (não
é um ponteiro pra um elemento da struct A), então tem espaço reservado no
começo dela pra caber todo o int foo dentro de acme. Portanto, se meep for
assim:

    struct A *meep = (A *)acme;

Você teria acesso ao int foo de dentro do acme, que é na verdade um struct
B, que não tem um int foo.

O que acontece aí é que não é que precisa de um new, é que precisa dum
ponteiro e um cast, mesmo que implícito (por causa da herança no C++).

Convém lembrar também que o primeiro trecho de código declarando meep e o
segundo declarando *meep não são compatíveis. Tanto em C quanto em C++, no
primeiro trecho, se acme e meep fossem do mesmo tipo, rolaria uma cópia. Em
C seria byte-a-byte mesmo -- e em C++ a mesma coisa, a não ser que tenha um
construtor de cópia, que seria chamado.

Voltando pro C++, aliás, se tivéssemos isso:

    auto foo = std::make_unique<A>();

E eu fizesse:

    auto bar = foo;

Isso aí daria pau, pois um std::unique_ptr<T>() não pode ser copiado.
Entretanto, se quisesse ter duas referências pra um mesmo struct A e não
ter que ficar sacando quem tá usando ou não pra saber qual é a hora de
matar, tem que usar um outro cara similar, chamado std::shared_ptr<T>. A
ideia é a mesma:

    auto foo = std::make_shared<A>();
    auto bar = foo;

Eu não estaria fazendo uma cópia do struct A, mas sim rodando o construtor
de cópia do std::shared_ptr<T>(), que na real faz exatamente o que o nome
diz: vai continuar existindo um único struct A que o std::make_shared()
alocou, mas a contagem de referência interna do std::shared_ptr<A> que ele
retornou vai ser incrementada na cópia. Na destrição, vai ser decrementada.
Se chegar em 0, o destrutor do struct A é chamado.

-- 
 Leandro
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://listas.tia.mat.br/pipermail/hsc-tia.mat.br/attachments/20160223/e2c5f2ac/attachment.html>


More information about the HSC mailing list