Domanda

Qualcuno sa come posso, nel codice C++ indipendente dalla piattaforma, impedire la creazione di un oggetto nell'heap?Cioè, per una classe "Foo", voglio impedire agli utenti di fare questo:

Foo *ptr = new Foo;

e consentire loro di fare solo questo:

Foo myfooObject;

Qualcuno ha qualche idea?

Saluti,

È stato utile?

Soluzione

La risposta di Nick è un buon punto di partenza, ma incompleto, poiché in realtà è necessario sovraccaricare:

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

(Una buona pratica di codifica suggerirebbe di sovraccaricare anche gli operatori delete e delete[] -- lo farei, ma dal momento che non verranno chiamati non lo è Veramente necessario.)

Pauldoo è anche corretto affermare che questo non sopravvive aggregandosi su Foo, sebbene sopravviva ereditando da Foo.Potresti fare qualche magia di meta-programmazione del modello per AIUTARE a prevenirlo, ma non sarebbe immune agli "utenti malvagi" e quindi probabilmente non vale la complicazione.La documentazione su come dovrebbe essere utilizzata e la revisione del codice per garantire che venga utilizzato correttamente sono l'unico modo al 100%.

Altri suggerimenti

Potresti sovraccaricare new per Foo e renderlo privato.Ciò significherebbe che il compilatore si lamenterebbe...a meno che tu non stia creando un'istanza di Foo sull'heap dall'interno di Foo.Per cogliere questo caso, potresti semplicemente non scrivere il nuovo metodo di Foo e quindi il linker si lamenterebbe di simboli indefiniti.

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

PS.Sì, lo so, è possibile aggirarlo facilmente.Non lo consiglio davvero, penso che sia una cattiva idea, stavo solo rispondendo alla domanda!;-)

Non so come farlo in modo affidabile e portatile.Ma..

Se l'oggetto è nello stack, potresti essere in grado di affermare all'interno del costruttore che il valore di "this" è sempre vicino al puntatore dello stack.Ci sono buone probabilità che l'oggetto sia in pila se questo è il caso.

Credo che non tutte le piattaforme implementino i propri stack nella stessa direzione, quindi potresti voler fare un test una tantum quando l'app inizia a verificare in che modo cresce lo stack.Oppure fai un po' di fondente:

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

@Nick

Questo potrebbe essere aggirato creando una classe che derivi o aggreghi Foo.Penso che ciò che suggerisco (sebbene non sia robusto) funzionerebbe comunque per le classi derivate e aggreganti.

Per esempio:

struct MyStruct {
    Foo m_foo;
};

MyStruct* p = new MyStruct();

Qui ho creato un'istanza di "Foo" sull'heap, ignorando il nuovo operatore nascosto di Foo.

Poiché le intestazioni di debug possono sovrascrivere la nuova firma dell'operatore, è preferibile utilizzare ...firme come rimedio completo:

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

Potresti dichiarare una funzione chiamata "operatore new" all'interno della classe Foo che bloccherebbe l'accesso alla forma normale di new.

E' questo il tipo di comportamento che desideri?

Potresti dichiararlo come interfaccia e controllare la classe di implementazione più direttamente dal tuo codice.

questo può essere evitato rendendo privati ​​i costruttori e fornendo un membro statico per creare un oggetto nello stack

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

questo renderà la creazione dell'oggetto sempre nello stack.

Non sono sicuro che questo offra opportunità in fase di compilazione, ma hai pensato di sovraccaricare l'operatore "nuovo" per la tua classe?

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top