Как предотвратить создание объекта в куче? - PullRequest
24 голосов
/ 14 августа 2008

Кто-нибудь знает, как я могу в независимом от платформы коде C ++ предотвратить создание объекта в куче? То есть для класса "Foo" я хочу запретить пользователям делать это:

Foo *ptr = new Foo;

и разрешите им только это:

Foo myfooObject;

У кого-нибудь есть идеи?

Приветствия

Ответы [ 9 ]

24 голосов
/ 14 августа 2008

Ответ Ника - хорошая отправная точка, но не полная, поскольку вам действительно нужно перегрузить:

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

(Хорошая практика кодирования предполагает, что вам также следует перегружать операторы delete и delete [] - я бы это сделал, но поскольку они не будут вызываться, это не действительно необходимо.)

Pauldoo также верно, что это не выживает, агрегируя на Foo, хотя оно выживает, наследуя от Foo. Вы могли бы сделать некоторую магию метапрограммирования шаблона, чтобы HELP предотвратил это, но он не был бы защищен от «злых пользователей» и, следовательно, вероятно, не стоит осложнений. Документация о том, как его следует использовать, и проверка кода, чтобы убедиться, что он используется должным образом, являются единственным ~ 100% способом.

9 голосов
/ 14 августа 2008

Вы можете перегрузить новый для Foo и сделать его приватным. Это будет означать, что компилятор будет стонать ... если только вы не создаете экземпляр Foo в куче из Foo. Чтобы поймать этот случай, вы можете просто не писать новый метод Foo, и тогда компоновщик будет жаловаться на неопределенные символы.

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

PS. Да, я знаю, что это можно легко обойти. Я действительно не рекомендую это - я думаю, что это плохая идея - я просто отвечал на вопрос! ; -)

7 голосов
/ 14 августа 2008

Я не знаю, как это сделать надежно и портативно ... но ..

Если объект находится в стеке, вы можете утверждать в конструкторе, что значение this всегда близко к указателю стека. В таком случае есть большой шанс, что объект окажется в стеке.

Я считаю, что не все платформы реализуют свои стеки в одном и том же направлении, поэтому вам может потребоваться выполнить однократный тест, когда приложение начнет проверять, как растет стек ... Или сделать некоторую помадку:

FooClass::FooClass() {
    char dummy;
    ptrdiff_t displacement = &dummy - reinterpret_cast<char*>(this);
    if (displacement > 10000 || displacement < -10000) {
        throw "Not on the stack - maybe..";
    }
}
3 голосов
/ 14 августа 2008

@ Ник

Этого можно избежать, создав класс, производный от Foo или объединяющий его. Я думаю, что то, что я предлагаю (хотя и не является надежным), все равно будет работать для производных и агрегирующих классов.

например:

struct MyStruct {
    Foo m_foo;
};

MyStruct* p = new MyStruct();

Здесь я создал экземпляр 'Foo' в куче, минуя скрытый новый оператор Foo.

2 голосов
/ 27 мая 2016

Поскольку заголовки отладки могут переопределять новую подпись оператора, лучше всего использовать подписи ... как полное средство:

private:
void* operator new(size_t, ...) = delete;
void* operator new[](size_t, ...) = delete;
0 голосов
/ 20 января 2018

этого можно избежать, сделав конструкторы частными и предоставив статический член для создания объекта в стеке

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

это сделает создание объекта всегда в стеке.

0 голосов
/ 14 августа 2008

Вы можете объявить его как интерфейс и более непосредственно управлять классом реализации из своего собственного кода.

0 голосов
/ 14 августа 2008

Не уверен, предлагает ли это какие-либо возможности времени компиляции, но вы смотрели на перегрузку оператора 'new' для вашего класса?

0 голосов
/ 14 августа 2008

Вы можете объявить функцию с именем "operator new" внутри класса Foo, которая блокирует доступ к нормальной форме new.

Это то поведение, которое вы хотите?

...