Question

Est-ce que quelqu'un sait comment je peux, dans un code C++ indépendant de la plate-forme, empêcher la création d'un objet sur le tas ?Autrement dit, pour une classe "Foo", je souhaite empêcher les utilisateurs de faire ceci :

Foo *ptr = new Foo;

et permettez-leur seulement de faire ceci :

Foo myfooObject;

Quelqu'un a-t-il une idée?

Acclamations,

Était-ce utile?

La solution

La réponse de Nick est un bon point de départ, mais incomplet, car il faut en fait surcharger :

private:
    void* operator new(size_t);          // standard new
    void* operator new(size_t, void*);   // placement new
    void* operator new[](size_t);        // array new
    void* operator new[](size_t, void*); // placement array new

(Une bonne pratique de codage suggère que vous devriez également surcharger les opérateurs delete et delete[] -- je le ferais, mais comme ils ne seront pas appelés, ce n'est pas le cas. vraiment nécessaire.)

Pauldoo Il est également exact que cela ne survit pas à l'agrégation sur Foo, bien qu'il survive à l'héritage de Foo.Vous pourriez faire un peu de magie de méta-programmation de modèles pour AIDE à empêcher cela, mais cela ne serait pas à l'abri des "utilisateurs malveillants" et n'en vaut donc probablement pas la peine.La documentation sur la façon dont il doit être utilisé et la révision du code pour garantir qu'il est utilisé correctement sont le seul moyen à environ 100 %.

Autres conseils

Vous pouvez surcharger new pour Foo et le rendre privé.Cela signifierait que le compilateur gémirait...sauf si vous créez une instance de Foo sur le tas depuis Foo.Pour résoudre ce cas, vous pourriez simplement ne pas écrire la nouvelle méthode de Foo et l'éditeur de liens se plaindrait alors des symboles non définis.

class Foo {
private:
  void* operator new(size_t size);
};

PS.Oui, je sais que cela peut être facilement contourné.Je ne le recommande vraiment pas - je pense que c'est une mauvaise idée - je répondais juste à la question !;-)

Je ne sais pas comment le faire de manière fiable et portable.mais..

Si l'objet est sur la pile, vous pourrez peut-être affirmer dans le constructeur que la valeur de « this » est toujours proche du pointeur de pile.Il y a de fortes chances que l'objet soit sur la pile si tel est le cas.

Je pense que toutes les plates-formes n'implémentent pas leurs piles dans la même direction, vous souhaiterez donc peut-être faire un test ponctuel lorsque l'application commence à vérifier dans quel sens la pile se développe.Ou faites du fudge :

FooClass::FooClass() {
    char dummy;
    ptrdiff_t displacement = &dummy - reinterpret_cast<char*>(this);
    if (displacement > 10000 || displacement < -10000) {
        throw "Not on the stack - maybe..";
    }
}

@Pseudo

Cela pourrait être contourné en créant une classe qui dérive ou regroupe Foo.Je pense que ce que je suggère (bien que non robuste) fonctionnerait toujours pour les classes dérivées et agrégées.

Par exemple:

struct MyStruct {
    Foo m_foo;
};

MyStruct* p = new MyStruct();

Ici, j'ai créé une instance de « Foo » sur le tas, en contournant le nouvel opérateur caché de Foo.

Étant donné que les en-têtes de débogage peuvent remplacer la nouvelle signature de l'opérateur, il est préférable d'utiliser le...les signatures comme remède complet :

private:
void* operator new(size_t, ...) = delete;
void* operator new[](size_t, ...) = delete;

Vous pouvez déclarer une fonction appelée "operator new" dans la classe Foo qui bloquerait l'accès à la forme normale de new.

Est-ce le genre de comportement que vous souhaitez ?

Vous pouvez le déclarer comme interface et contrôler la classe d'implémentation plus directement à partir de votre propre code.

cela peut être évité en rendant les constructeurs privés et en fournissant un membre statique pour créer un objet dans la pile

Class Foo
{
    private:
        Foo();
        Foo(Foo& );
    public:
        static Foo GenerateInstance() { 
            Foo a ; return a; 
        }
}

cela rendra la création de l'objet toujours dans la pile.

Vous ne savez pas si cela offre des opportunités de compilation, mais avez-vous envisagé de surcharger le « nouvel » opérateur pour votre classe ?

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top