В своих поисках в Интернете я наткнулся на эта почта, который включает в себя
"(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++, но попутно, никогда ничего серьезного, но мне просто любопытно, что именно это означает?
Может кто-нибудь привести пример?





Переменные в C++ могут быть объявлены в стеке или куче. Когда вы объявляете переменную в C++, она автоматически попадает в стек, если вы явно не используете оператор new (он попадает в кучу).
MyObject x = MyObject(params); // onto the stack
MyObject * y = new MyObject(params); // onto the heap
Это имеет большое значение в способе управления памятью. Когда переменная объявляется в стеке, она освобождается, когда выходит за пределы области видимости. Переменная в куче не будет уничтожена до тех пор, пока для объекта не будет явно вызвано удаление.
Автоматический стек - это переменные, которые размещаются в стеке текущего метода. Идея разработки класса, который может действовать как автоматический стек, заключается в том, что должна быть возможность полностью инициализировать его одним вызовом и уничтожить другим. Важно, чтобы деструктор освободил все ресурсы, выделенные объектом, а его конструктор возвращал объект, который был полностью инициализирован и готов к использованию. Аналогично для операции копирования - класс должен иметь возможность легко создавать копии, которые являются полностью функциональными и независимыми.
Использование такого класса должно быть аналогично тому, как используются примитивы 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).
Просто небольшая проблема с формулировкой: каждая переменная уничтожается, когда ее область действия / время жизни исчерпаны, поэтому на самом деле obj*b "уничтожается". Его деструктор ничего не делает, поэтому new obj не удаляется. Просто изменив тип указателя на, т.е. smart_ptr<obj>, у которого есть деструктор, область видимости не изменяется, но объекты удаляются.
В дополнение к другим ответам:
В языке 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, удаленным), чтобы предотвратить его автоматический вызов, что приведет к двойному освобождению от принадлежащего ресурса. Правило трех не говорит, что вы должны определить конструктор копирования, оно говорит, что вы должны запретить компилятору определить его (либо предоставив свой собственный, либо сделав его недоступным / удаленным).
Вообще-то там нужно быть осторожным. Несмотря на то, что все мы знаем, что глобальные данные - это плохо, не забывайте о сегментах данных (инициализированных) и BSS (неинициализированных), где находятся глобальные / статические данные.