[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[linux] Re: [C++] Re: C++ / C re-question



Hello !

On Fri, Jul 13, 2001 at 09:05:19AM +0200, Pascal Bleser wrote:
[.../...] 
> En général, vaut mieux éviter ce genre de trucs (et surtout char*) et utiliser
> soit std::string de la STL, soit un smart pointer, du genre

J'ai du mal à comprendre pourquoi les « novices » du C++ ¹ ont si peur
de 'std::string' ... et pourquoi les professeurs ne les poussent pas
plus à comprendre le mécanisme.

Pour ceux qui ne le savent pas, copier une instance de 'std::string' (ou
la passer par valeur) reste _très performant_. Certainement plus
performant que la solution traditionnelle du C, où l'on fait des
'strdup' et des 'free' à tire-larigot. En effet, les chaînes de
'std::string' sont copy-on-write, c'est-à-dire qu'elles ne sont copiées
que lorsque c'est _strictement_ nécessaire, donc lors des rares
modifications.

> template <class T>
> class SmartPointer {
> private:
>   T* pointer_;
> public:
>   SmartPointer(T* pointer) : pointer_(pointer) { }
>   SmartPointer(const SmartPointer& sp)
>     : pointer_(sp.pointer) { }
> 
>   virtual ~SmartPointer() {
>     delete pointer_;
>   }  
> 
>   T* operator->() const {
>     return pointer_;
>   }
> };
> 
> L'astuce étant que lorsque le SmartPointer est out of scope, il va faire
> un delete sur le pointer.

Pas bien ... il manque un compteur d'instance par pointeur ;)

Pour ceux que cela « tracasse » : la classe SmartPointer contient un
constructeur de copie, et donc va donc être copiée à tout va (retours de
fonction, variables locales, etc.). Mais l'expression 'delete pointer_;'
va être exécutée dès que la _1ere_ instance va être out of scope ! Donc,
les autres pointeurs deviendront indéterminés, et plusieurs 'delete'
seront faits sur la même zone mémoire.

Mais l'idée reste astucieuse : j'ai un peu étoffé la classe de Pascal,
(et j'ai fait un petit programme de test, pour éviter les mauvaises
surprises), et je l'ai mise en attachement. Si qqn a des commentaires,
qu'il n'hésite pas à me le faire savoir. ²

Cu,
Dash.

¹ Bon, OK, j'en fais partie.
² En privé, sinon il va vraîment falloir créer une liste C++ sur
linuxbe !

-- 
Convictions are more dangerous enemies of truth than lies.
                -- Nietzsche
-- 
Damien Diederen
dash@linuxbe.org
http://users.swing.be/diederen/
#include <iostream>
#include <string>

template <class T>
struct SmartPointerNode {
public:
        SmartPointerNode (T* pointer) :
                mPointer (pointer), mCount (1) { }
private:
        SmartPointerNode (const SmartPointerNode& o)
                { }

public:
        T* mPointer;
        int mCount;
};

template <class T>
class SmartPointer {
public:
        SmartPointer (T* pointer)
                { mNode = new SmartPointerNode<T> (pointer); }
        SmartPointer (const SmartPointer& o) :
                mNode (o.mNode)
                { ++ mNode->mCount; }
        ~SmartPointer () {
                if (-- mNode->mCount == 0) {
                        delete mNode->mPointer;
                        delete mNode;
                }
        }

        T* operator-> () const
                { return mNode->mPointer; }

private:
        SmartPointerNode<T>* mNode;
};

class Foo {
public:
        Foo () { cout << "Foo constructed" << endl; }
        ~Foo () { cout << "Foo destroyed" << endl; }

        void sayHello (const std::string& from) const
                { cout << "Foo says Hello from " << from << endl; }
};

typedef SmartPointer<Foo> FooPtr;

FooPtr makeFoo ()
{
        FooPtr f = new Foo ();

        f->sayHello ("makeFoo");

        return f;
}

void useFoo (FooPtr sf)
{
        FooPtr f = sf;

        f->sayHello ("useFoo");
}

int main ()
{
        FooPtr f = makeFoo ();

        f->sayHello ("main");

        useFoo (f);
        
        return 0;
}