C++ - Что означает «автоматический стек»?

В своих поисках в Интернете я наткнулся на эта почта, который включает в себя

"(Well written) C++ goes to great lengths to make stack automatic objects work "just like" primitives, as reflected in Stroustrup's advice to "do as the ints do". This requires a much greater adherence to the principles of Object Oriented development: your class isn't right until it "works like" an int, following the "Rule of Three" that guarantees it can (just like an int) be created, copied, and correctly destroyed as a stack automatic."

Я написал немного кода на C и C++, но попутно, никогда ничего серьезного, но мне просто любопытно, что именно это означает?

Может кто-нибудь привести пример?

Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
4
0
908
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

Переменные в C++ могут быть объявлены в стеке или куче. Когда вы объявляете переменную в C++, она автоматически попадает в стек, если вы явно не используете оператор new (он попадает в кучу).

MyObject x = MyObject(params); // onto the stack

MyObject * y = new MyObject(params); // onto the heap

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

Вообще-то там нужно быть осторожным. Несмотря на то, что все мы знаем, что глобальные данные - это плохо, не забывайте о сегментах данных (инициализированных) и BSS (неинициализированных), где находятся глобальные / статические данные.

Dan 02.12.2010 07:25

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

Использование такого класса должно быть аналогично тому, как используются примитивы int, float и т. д. Вы определяете их (в конечном итоге даете им некоторое начальное значение), а затем передаете их и, в конце концов, оставляете компилятор для очистки.

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

Компилятор автоматически обрабатывает объекты стека.

Когда область покидает, она удаляется.

{
   obj a;
} // a is destroyed here

Когда вы делаете то же самое с «новым» объектом, вы получаете утечку памяти:

{
    obj* b = new obj;
}

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

В C часто встречается следующее:

{
   FILE* pF = fopen( ... );
   // ... do sth with pF
   fclose( pF );
}

В C++ мы пишем это:

{
   std::fstream f( ... );
   // do sth with f
} // here f gets auto magically destroyed and the destructor frees the file

Когда мы забываем вызвать fclose в примере C, файл не закрывается и не может использоваться другими программами. (например, его нельзя удалить).

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

{
   string v( "bob" );
   string k;

   v = k
   // v now contains "bob"
} // v + k are destroyed here, and any memory used by v + k is freed

Эта функция широко используется в C++ для автоматического управления сбором и выпуском ресурсов с помощью идиомы Resource Acquisition Is Initialization (RAII).

Luc Touraille 25.09.2008 12:58

Просто небольшая проблема с формулировкой: каждая переменная уничтожается, когда ее область действия / время жизни исчерпаны, поэтому на самом деле obj*b "уничтожается". Его деструктор ничего не делает, поэтому new obj не удаляется. Просто изменив тип указателя на, т.е. smart_ptr<obj>, у которого есть деструктор, область видимости не изменяется, но объекты удаляются.

quetzalcoatl 09.08.2012 17:49

В дополнение к другим ответам:

В языке C++ на самом деле есть ключевое слово auto для явного объявления класса хранения объекта. Конечно, в этом нет никакой необходимости, потому что это подразумеваемый класс хранения для локальных переменных, и его нельзя нигде использовать. Противоположностью auto является static (как локально, так и глобально).

Следующие два объявления эквивалентны:

int main() {
    int a;
    auto int b;
}

Поскольку ключевое слово совершенно бесполезно, оно будет фактически переработано в следующем стандарте C++ («C++ 0x») и получит новое значение, а именно позволяет компилятору определить тип переменной из ее инициализации (например, var в C#). :

auto a = std::max(1.0, 4.0); // `a` now has type double.

Поправьте меня, если я ошибаюсь, но я думаю, что операция копирования не является обязательной, чтобы в полной мере использовать автоматическую очистку стека. Например, рассмотрим классический объект MutexGuard, ему не нужна операция копирования, чтобы использовать его как автоматический стек, или нет?

Это правильно. Вы все равно должны объявить конструктор копирования закрытым (или в C++ 0x, удаленным), чтобы предотвратить его автоматический вызов, что приведет к двойному освобождению от принадлежащего ресурса. Правило трех не говорит, что вы должны определить конструктор копирования, оно говорит, что вы должны запретить компилятору определить его (либо предоставив свой собственный, либо сделав его недоступным / удаленным).

Ben Voigt 05.12.2010 07:13

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