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

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

Foo *ptr = new Foo;

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

Foo myfooObject;

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

Ура,

14.08.2008 13:19:08
Почему вы хотите это сделать?
David Rodríguez - dribeas 19.08.2010 12:29:14
Реверс, который также может быть интересен читателям: stackoverflow.com/questions/124880/…
kevinarpe 16.08.2016 14:37:15
9 ОТВЕТОВ
РЕШЕНИЕ

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

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. Вы могли бы применить магию метапрограммирования шаблона, чтобы HELP предотвратил это, но он не был бы невосприимчив к «злым пользователям» и, таким образом, вероятно, не стоит осложнений. Документация о том, как его следует использовать, и проверка кода, чтобы убедиться, что он используется должным образом, - это единственный ~ 100% способ.

25
23.05.2017 12:02:06
Достигнет ли тот же самый частный конструктор в сочетании с общедоступным статическим методом фабрики (возврат по значению)?
kevinarpe 16.08.2016 14:55:36
@kevinarpe Это зависит от того, насколько буквально мы читаем вопрос. Точный код Foo myfooObject;из вопроса не скомпилируется, если вы это сделаете. Тем не менее, я предпочитаю подход, более похожий на то, что вы предлагаете, если я пытаюсь контролировать, как создаются объекты.
Patrick Johnmeyer 22.08.2016 18:56:51
Обратите внимание, что это можно обойти, используя ::newвместо того new, чтобы выполнить поиск operator newв глобальной области видимости.
Brian 27.09.2018 19:46:41

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

Вы хотите такое поведение?

0
14.08.2008 13:28:17

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

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

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

9
14.08.2008 14:04:34

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

-1
14.08.2008 13:35:29

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

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

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

FooClass::FooClass() {
    char dummy;
    ptrdiff_t displacement = &dummy - reinterpret_cast<char*>(this);
    if (displacement > 10000 || displacement < -10000) {
        throw "Not on the stack - maybe..";
    }
}
7
14.08.2008 13:40:34
Я думаю, что эта и пустышка всегда будут рядом друг с другом, независимо от того, находятся ли они в куче или в стеке
Vargas 1.07.2010 20:29:04
@ Варгас - я не согласен. 'dummy' всегда будет в стеке, потому что это автоматическая локальная переменная. thisУказатель может указывать на любой из стека (если FooClass используется в качестве локальной переменной) или в куче (если FooClass выделяется в куче, или агрегирование внутри класса , который затем выделяется в куче).
pauldoo 2.07.2010 09:01:21
Вы правы, я принял dummyза переменную-член ... извините
Vargas 2.07.2010 18:56:27

@Ник

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

Например:

struct MyStruct {
    Foo m_foo;
};

MyStruct* p = new MyStruct();

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

3
14.08.2008 13:52:48

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

0
14.08.2008 13:41:58

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

private:
void* operator new(size_t, ...) = delete;
void* operator new[](size_t, ...) = delete;
2
26.05.2016 22:34:20

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

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

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

0
20.01.2018 20:11:51