Можно ли предотвратить выделение объекта в стеке и разрешить его создание только с помощью 'new'?

Можно ли предотвратить выделение объекта в стеке и разрешить ему создавать только «новый» в куче?

Обратное, что тоже может быть интересно читателям: stackoverflow.com/questions/10985/…

kevinarpe 16.08.2016 17:36
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
53
1
12 231
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

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

Ответ принят как подходящий

Один из способов сделать это - сделать конструкторы закрытыми и разрешить построение только с помощью статического метода, возвращающего указатель. Например:

class Foo
{
public:
    ~Foo();
    static Foo* createFoo()
    {
        return new Foo();
    }
private:
    Foo();
    Foo(const Foo&);
    Foo& operator=(const Foo&);
};

Или еще лучше статическая функция, которая возвращает std :: unique_ptr <Foo>.

user213313 03.10.2012 00:43

Но зачем делать его и непередаваемым?

Deduplicator 19.02.2015 01:34

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

Daemin 24.02.2015 06:57

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

// Header file

class IAbstract
{
    virtual void AbstractMethod() = 0;

public:
    virtual ~IAbstract();
};

IAbstract* CreateSubClassA();
IAbstract* CreateSubClassB();

// Source file

class SubClassA : public IAbstract
{
    void AbstractMethod() {}
};

class SubClassB : public IAbstract
{
    void AbstractMethod() {}
};

IAbstract* CreateSubClassA()
{
    return new SubClassA;
}

IAbstract* CreateSubClassB()
{
    return new SubClassB;
}

В случае C++ 11

class Foo
{
  public:
    ~Foo();
    static Foo* createFoo()
    {
        return new Foo();
    }

    Foo(const Foo &) = delete; // if needed, put as private
    Foo & operator=(const Foo &) = delete; // if needed, put as private
    Foo(Foo &&) = delete; // if needed, put as private
    Foo & operator=(Foo &&) = delete; // if needed, put as private

  private:
    Foo();
};

Как сказал Скотт Мейерс в «Правиле 11: Предпочитайте удаленные функции частным неопределенным». В своей книге «Эффективный современный C++» лучше объявить удаленные функции-члены public. --QUOTE-- «По соглашению, удаленные функции объявляются public, а не private. Для этого есть причина. Когда клиентский код пытается использовать функцию-член, C++ проверяет доступность перед удаленным статусом. Когда клиентский код пытается использовать удалена функция private, некоторые компиляторы жалуются только на то, что эта функция является private, хотя доступность функции не влияет на возможность ее использования ».

Siu Ching Pong -Asuka Kenji- 28.03.2015 18:10

--QUOTE-- «Это стоит иметь в виду при пересмотре устаревшего кода, чтобы заменить функции-члены private и не определенные функции-члены удаленными, потому что создание новых функций public обычно приводит к более качественным сообщениям об ошибках».

Siu Ching Pong -Asuka Kenji- 28.03.2015 18:13

Должен. Дайте. Моар. Вверх. Голоса.

kevinarpe 16.08.2016 17:57

Следующее разрешает общедоступные конструкторы и остановит выделение стека, выбрасывая во время выполнения. Примечание thread_local - это ключевое слово C++ 11.

class NoStackBase {
    static thread_local bool _heap;
protected:
    NoStackBase() {
        bool _stack = _heap;
        _heap = false;
        if (_stack)
            throw std::logic_error("heap allocations only");
    }
public:
    void* operator new(size_t size) throw (std::bad_alloc) { 
        _heap = true;
        return ::operator new(size);
    }
    void* operator new(size_t size, const std::nothrow_t& nothrow_value) throw () {
        _heap = true;
        return ::operator new(size, nothrow_value);
    }
    void* operator new(size_t size, void* ptr) throw () {
        _heap = true;
        return ::operator new(size, ptr);
    }
    void* operator new[](size_t size) throw (std::bad_alloc) {
        _heap = true;
        return ::operator new[](size);
    }
    void* operator new[](size_t size, const std::nothrow_t& nothrow_value) throw () {
        _heap = true;
        return ::operator new[](size, nothrow_value);
    }
    void* operator new[](size_t size, void* ptr) throw () {
        _heap = true;
        return ::operator new[](size, ptr);
    }
};

bool thread_local NoStackBase::_heap = false;

Я не думаю, что вам нужен _stack в качестве члена данных. Достаточно иметь его как простую переменную стека внутри конструктора NoStackBase.

Paul J. Lucas 25.01.2016 18:16

Также не нужно делать деструктор virtual. В любом случае никто не может удалить производный класс через NoStackBase.

Paul J. Lucas 25.01.2016 18:48

поскольку вы явно вызываете глобальный оператор new, я предполагаю, что это не вызовет перегрузки какого-либо настраиваемого оператора, которые определены этими объектами (?), и принуждение к их использованию может быть мотивирующей причиной для этого вопроса

Joseph Garvin 24.01.2020 19:00

Это должно быть возможно в C++ 20 с использованием разрушающего оператора delete, см. p0722r3.

#include <new>

class C
{
private:
  ~C() = default;
public:
  void operator delete(C *c, std::destroying_delete_t)
  {
    c->~C();
    ::operator delete(c);
  }
};

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

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