Деструкторы в C ++ (по сравнению с Java) - PullRequest
3 голосов
/ 13 февраля 2012

До сих пор я писал программы на Java. Поэтому, когда я запустил C ++, первое, что мне пришло в голову, это как уничтожить / удалить / завершить объекты, которые мне больше не нужны.

В Java я использовал для них значение null, поэтому сборщик мусора позаботился об этом. Тем не менее, я не знаю, как обстоят дела с C ++. Я нашел эту статью http://en.wikipedia.org/wiki/Comparison_of_Java_and_C%2B%2B, которая решила большинство моих вопросов. Но есть еще несколько вещей, которые я не понял.

1) В Java есть способ заставить сборщик мусора произвести очистку прямо на месте (что не всегда полезно, так как перед запуском он ожидает накопления нескольких мусоров). Есть ли способ сделать это с C ++?

2) (C ++) Также как и наоборот, как я могу сделать так, чтобы я поместил объект в состояние «помечен для удаления», и программа решает, когда его очистить (например, Java)?

3) (C ++) Должен ли я заставить сборщик мусора убирать прямо на месте (я уверен, что это не правильный путь, но я просто хочу быть уверенным)?

Я бы оценил это, если бы вы могли привести небольшой пример кода, с помощью которого какой код запускает.

Ответы [ 5 ]

6 голосов
/ 13 февраля 2012

1) Если ваши объекты находятся в автоматическом хранилище, вы можете ограничить их область действия:

{
   X x;
   //...
}  //x gets destructed here

Если в динамическом хранилище вы удалите их, когда закончите:

X* x = new X;
//...
delete x; //x gets destructed

2) Вы не можете (по крайней мере, в чистом виде).Вы должны указать C ++, когда удалять ваши объекты, даже если эта инструкция состоит из конечной скобки.(см. первый фрагмент кода)

3) В C ++ нет сборщика мусора.Смотрите два фрагмента.Вы должны либо явно удалить объекты (если они находятся в динамическом хранилище), либо они будут удалены автоматически (но не сборщиком мусора), если они находятся в автоматическом хранилище.

Что-то, на что стоит обратить внимание, это умные указатели (естьЕсть множество реализаций), но это также не сборщик мусора.Это просто избавляет вас от необходимости управлять памятью.Но это не похоже на Java.

4 голосов
/ 13 февраля 2012

C ++ сильно отличается от Java в этой области, поэтому вот краткий обзор:

выделение: память выделена для объекта.
Строительство: объект готов к использованию.
разрушение: объект «заканчивает» все и разбирает сам себя.
освобождение: память возвращается в систему.

int main() {
    int myint;  //automatic int object is allocated and constructed
    //stuff
}   // when main ends, automatic int object is destroyed and deallocated

int main() {
    int* mypointer;  //automatic pointer object is allocated and constructed
    mypointer = new int;  //dynamic int object is allocated and constructed
    //stuff
    delete mypointer; //dynamic int object is destroyed and deallocated 
}   // when main ends, automatic pointer object is destroyed and deallocated
    // note: Pointers to _not_ delete the object they point to.

class myclass {
    //members
public:
    myclass() {} //this is the default constructor
    myclass(const myclass& rhs) {} //this is the copy constructor
    myclass& operator=(const myclass& rhs) {return *this} //this is the assignment operator
    ~myclass() {} //this is the destructor
};

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

Если вы распределяете вещи вручную (с ключевым словом new), они должны быть уничтожены и освобождены вручную с помощью ключевого слова delete. Когда вы звоните delete, он тут же уничтожает (и освобождает) и не будет продолжать, пока это не будет сделано. Если вы забудете, он НИКОГДА НЕ ПОЛУЧИТСЯ (хотя некоторые операционные системы освободят его после завершения вашей программы).

Поскольку люди делают ошибки, «правильная» вещь, которую нужно делать, когда вам нужны динамические объекты:

int main() {
    std::unique_ptr<myclass> myptr = new myclass(); //allocate and construct
} //both the unique_ptr and the dynamic object are destroyed and deallocated

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

Причина, по которой это делает C ++, заключается в том, что если у вас есть объект F, представляющий этот файл, он может иметь эксклюзивную блокировку этого файла. В C ++ после уничтожения F вы можете немедленно создать объект G, который использует тот же файл. В Java нет гарантии, что finalizer будет когда-либо работать, а это означает, что файл может оставаться заблокированным до завершения вашей программы. (Маловероятно, но возможно)

3 голосов
/ 13 февраля 2012

В C ++ нет сборщика мусора. Вы должны писать и запускать деструкторы самостоятельно. В C ++ распространенная ошибка - забыть запустить деструктор.

Если ваш объект выделен с new, то вы должны удалить его с delete. Итак, new вызывает конструктор, а delete вызывает деструктор.

myclass *p = new myclass();
// do something
delete p;

Это называется динамическим размещением объектов.

Если ваш объект определен как "обычный", он будет автоматически уничтожен, когда выйдет за рамки.

myclass a;
// do something
// will destructed when }

Это называется автоматическим распределением объектов.

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

1 голос
/ 13 февраля 2012

C ++ использует идиому программирования RAII (Resource Acquisition Is Initialization), нет ничего лучше автоматического управления памятью, известного как сборщик мусора в java или AutoZone в Objective-C 2. Таким образом, надлежащая очистка экземпляра может легко усложниться.Чтобы ответить на ваши вопросы:

объявление 1: в C ++ нет GC, поэтому вы должны удалить свои объекты вручную или использовать метод подсчета ссылок или более эффективные интеллектуальные указатели, которые теперь являются частью стандарта C ++ 11,но, насколько я знаю, он пока недоступен ни в одном компиляторе C ++.На данный момент вы можете использовать шаблоны Smart Pointer из библиотеки Boost: http://www.boost.org/doc/libs/1_48_0/libs/smart_ptr/smart_ptr.htm. Новый стандарт C ++ напрямую использует реализацию Boost, поэтому при переходе на новый стандарт в ближайшем будущем проблем не возникнет (MSVC 2012 внедрит C ++11 поддержка).

объявление 2: маркировка невозможна, просто удалите ее «вручную» в нужном месте или оставьте это задание на интеллектуальных указателях.

объявление 3: не применимо.

Наконец, всегда есть самый простой вариант - не размещать ваши объекты в куче, что означает динамически.В Java такой возможности нет, но в C ++ она есть.Я даже читал в некоторых великих книгах Страуструпа (создателя C ++) по программированию на C ++, что во время создания C ++ такое динамическое распределение не было рекомендовано.Он заявил: для правильной работы RAII не должно быть динамического распределения - сегодня это звучит странно, но это то, что написал Страуструп, это не из моей головы, я лично динамически распределяю почти все, как это делают все ...

Основная причина статического размещения состоит в том, что объекты удаляются, когда они выходят за пределы области видимости, поэтому не нужно беспокоиться о безопасности и очистке исключений.Если вы выделяете экземпляр динамически, он не удаляется автоматически, если экземпляр покидает текущую область - у вас есть утечка памяти - если вы не удаляете экземпляр вручную.Рассмотрим простой блок try-catch:

try 
{
Class *instance = new Class;
//some error
}
catch(...)
{
//error caught - current execution is terminated immediately, instance is no deleted - memory leak.
}

В Java существует оператор finally, который всегда вызывается, чтобы вы могли выполнить необходимую очистку при возникновении исключения.Но в C ++ у вас проблемы ... , если вы не используете упомянутые умные указатели или какую-то очень похожую технику. При использовании умных указателей вам больше не нужно беспокоиться об очистке (не совсем так на практике,но ваша жизнь определенно станет проще, а ваш код будет менее глючным).

1 голос
/ 13 февраля 2012

Сборка мусора в C ++ всегда немедленная. Там нет отдельного сборщика мусора; когда вы удаляете объект, он сразу удаляется в текущем потоке. Это выглядит так:

MyObject* foo = new MyObject();
...
delete foo;

Для C ++ доступны платформы сборки мусора, и вы также можете посмотреть на умные указатели, которые также являются формой сборки мусора.

Обратите внимание на комментарии Джеймса ниже - деструктор и оператор delete для объекта всегда вызываются немедленно, но это зависит от реализации того, будет ли память доступна сразу.

...