Jak zapobiec utworzeniu obiektu na stercie?

Czy ktoś wie jak Mogę w niezależnym od platformy kodzie C++ zapobiec tworzeniu obiektu na stercie? Oznacza to, że dla klasy " Foo " chcę uniemożliwić użytkownikom robienie tego:

Foo *ptr = new Foo;

I tylko pozwolić im to zrobić:

Foo myfooObject;
Czy ktoś ma jakieś pomysły? Zdrówko, zdrówko]}
Author: SCFrench, 2008-08-14

9 answers

Odpowiedź Nicka jest dobrym punktem wyjścia, ale niekompletnym, ponieważ faktycznie trzeba przeciążać:

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

(Dobra praktyka kodowania sugerowałaby również Przeciążenie operatorów delete I delete [] - ja bym to zrobił , ale ponieważ nie zostaną wywołani, nie jest to naprawdę {7]} konieczne.)

Pauldoo jest również poprawne, że to nie przetrwa agregacji na Foo, chociaż przeżyje dziedziczenie po Foo. Mógłbyś zrobić meta-programowanie szablonów magia, aby zapobiec temu, ale nie będzie odporny na "złych użytkowników" i dlatego prawdopodobnie nie jest warta komplikacji. Dokumentacja tego, jak powinien być używany, oraz przegląd kodu, aby upewnić się, że jest używany prawidłowo, są jedynym ~100% sposobem.

 28
Author: Patrick Johnmeyer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:02:06

Możesz przeciążyć new Dla Foo i uczynić to prywatnym. Oznaczałoby to, że kompilator jęczy... chyba że tworzysz instancję Foo na stercie z poziomu Foo. Aby złapać ten przypadek, po prostu nie można napisać nowej metody Foo, a następnie linker jęczy o niezdefiniowanych symbolach.

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

PS. Tak, Wiem, że można to łatwo obejść. Naprawdę nie polecam - myślę, że to zły pomysł - właśnie odpowiadałem na pytanie! ;-)

 10
Author: Nick,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-14 14:04:34

Nie wiem, jak to zrobić niezawodnie i w przenośny sposób.. ale..

Jeśli obiekt znajduje się na stosie, możesz być w stanie stwierdzić wewnątrz konstruktora, że wartość 'this' jest zawsze blisko wskaźnika stosu. Istnieje duża szansa, że obiekt będzie na stosie, jeśli tak się stanie.

Uważam, że nie wszystkie platformy wdrażają swoje stosy w tym samym kierunku, więc możesz zrobić jednorazowy test, gdy aplikacja zacznie sprawdzać, w którą stronę rośnie stos.. Albo zrobić krówkę:

FooClass::FooClass() {
    char dummy;
    ptrdiff_t displacement = &dummy - reinterpret_cast<char*>(this);
    if (displacement > 10000 || displacement < -10000) {
        throw "Not on the stack - maybe..";
    }
}
 7
Author: pauldoo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-14 13:40:34

@ Nick

Można to obejść, tworząc klasę, która wywodzi się z lub agreguje Foo. Myślę, że to, co sugeruję (choć nie solidne) nadal będzie działać dla klas pochodnych i agregujących.

Np:

struct MyStruct {
    Foo m_foo;
};

MyStruct* p = new MyStruct();

Tutaj stworzyłem instancję 'Foo' na stercie, omijając Ukryty nowy operator Foo.

 3
Author: pauldoo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-14 13:52:48

Ponieważ nagłówki debugowania mogą nadpisać nowy podpis operatora, najlepiej jest użyć ... podpisy jako kompletne rozwiązanie:

private:
void* operator new(size_t, ...) = delete;
void* operator new[](size_t, ...) = delete;
 2
Author: MerkX,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-26 22:34:20

Możesz zadeklarować funkcję o nazwie "operator new" wewnątrz klasy Foo, która zablokuje dostęp do normalnej postaci new.

Czy tego typu zachowanie chcesz ?

 0
Author: David,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-14 13:28:17

Możesz zadeklarować go jako interfejs i sterować klasą implementacji bardziej bezpośrednio z własnego kodu.

 0
Author: Lasse V. Karlsen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-14 13:41:58

Można temu zapobiec, czyniąc konstruktory prywatnymi i udostępniając statyczny element do tworzenia obiektu w stosie

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

Spowoduje to, że utworzenie obiektu będzie zawsze w stosie.

 0
Author: Bala,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-20 20:11:51

Nie jesteś pewien, czy to daje jakieś możliwości kompilacji, ale czy przyjrzałeś się przeciążeniu' nowego ' operatora dla twojej klasy?

 -1
Author: Will Dean,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-14 13:35:29