Как предотвратить создание объекта в куче?

StackOverflow https://stackoverflow.com/questions/10985

  •  08-06-2019
  •  | 
  •  

Вопрос

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

Foo *ptr = new Foo;

и позволять им делать это только:

Foo myfooObject;

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

Ваше здоровье,

Это было полезно?

Решение

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

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[] - я бы так и сделал, но поскольку они не будут вызываться, это не так в самом деле необходимо.)

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

Другие советы

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

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

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

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

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

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

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

@Ник

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

Например,:

struct MyStruct {
    Foo m_foo;
};

MyStruct* p = new MyStruct();

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

Поскольку заголовки debug могут переопределять сигнатуру operator new, лучше всего использовать ...подписи как комплексное средство правовой защиты:

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

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

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

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top