Как предотвратить создание объекта в куче?
Кто-нибудь знает, как я могу, в платформенно-независимом коде С++ предотвратить создание объекта в куче? То есть для класса "Foo" я хочу, чтобы пользователи этого не делали:
Foo *ptr = new Foo;
и разрешите им это сделать:
Foo myfooObject;
Есть ли у кого-нибудь идеи?
Приветствия,
Ответы
Ответ 1
Ответ Ник - хорошая отправная точка, но неполная, поскольку вам действительно нужно перегружать:
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. Вы можете сделать магию мета-программирования шаблона, чтобы ПОМОЩЬ предотвратить это, но это не будет застраховано от "злых пользователей" и, следовательно, вероятно, не стоит осложнений. Документация о том, как его использовать, и обзор кода, чтобы убедиться, что он используется правильно, - это всего лишь 100% -ный способ.
Ответ 2
Вы можете перегрузить новый для Foo и сделать его приватным. Это означало бы, что компилятор будет стонать... если вы не создадите экземпляр Foo в куче из Foo. Чтобы поймать этот случай, вы просто не могли написать новый метод Foo, а затем компоновщик будет стонать о символах undefined.
class Foo {
private:
void* operator new(size_t size);
};
PS. Да, я знаю, что это можно легко обойти. Я действительно не рекомендую это - я думаю, что это плохая идея - я просто отвечал на этот вопрос!; -)
Ответ 3
Я не знаю, как сделать это надежно и переносимым способом.. но..
Если объект находится в стеке, вы можете утверждать в конструкторе, что значение 'this' всегда близко к указателю на стек. Хорошая вероятность того, что объект будет находиться в стеке, если это так.
Я считаю, что не все платформы реализуют свои стеки в одном и том же направлении, поэтому вы можете сделать одноразовое тестирование, когда приложение начнет проверять, к какому способу растет стек. Или сделайте некоторые выдумки:
FooClass::FooClass() {
char dummy;
ptrdiff_t displacement = &dummy - reinterpret_cast<char*>(this);
if (displacement > 10000 || displacement < -10000) {
throw "Not on the stack - maybe..";
}
}
Ответ 4
@Nick
Это можно обойти, создав класс, который происходит или объединяет Foo. Я думаю, что то, что я предлагаю (хотя и не надежное), по-прежнему будет работать на производные и агрегирующие классы.
например:
struct MyStruct {
Foo m_foo;
};
MyStruct* p = new MyStruct();
Здесь я создал экземпляр "Foo" в куче, минуя Foo скрытый новый оператор.
Ответ 5
Вы можете объявить его как интерфейс и управлять классом реализации более непосредственно из своего собственного кода.
Ответ 6
Поскольку заголовки отладки могут переопределять новую подпись оператора, лучше всего использовать... подписи в качестве полного средства защиты:
private:
void* operator new(size_t, ...) = delete;
void* operator new[](size_t, ...) = delete;
Ответ 7
это можно предотвратить, сделав конструкторы частными и предоставив статический член для создания объекта в стеке
Class Foo
{
private:
Foo();
Foo(Foo& );
public:
static Foo GenerateInstance() {
Foo a ; return a;
}
}
это сделает создание объекта всегда в стеке.
Ответ 8
Вы можете объявить функцию "operator new" внутри класса Foo, которая блокирует доступ к нормальной форме нового.
Это то, что вам нужно?
Ответ 9
Не уверен, что это дает какие-либо возможности для компиляции, но посмотрели ли вы на перегрузку "нового" оператора для своего класса?