Как я могу назвать деструктор класса? - PullRequest
8 голосов
/ 27 октября 2010

У меня есть простой код C ++, но я не знаю, как использовать деструктор:

class date {

public:
    int day;
    date(int m)
    {
        day =m;
    }

    ~date(){
    cout << "I wish you have entered the year \n" << day;    
    }
};


int main()
{
  date ob2(12);
  ob2.~date();
  cout << ob2.day;
  return 0;
}

Вопрос, который у меня возникает, что я должен написать в своем коде деструктора,что после вызова деструктора он удалит переменную day ?

Ответы [ 7 ]

16 голосов
/ 27 октября 2010

Редко вам когда-нибудь нужно явно вызывать деструктор.Вместо этого деструктор вызывается, когда объект уничтожается.

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

int main() 
{ 
    date ob2(12); 

} // ob2.~date() is called here, automatically!

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

Если вы не создаете что-то динамически, используя new, вам не нужно ничего делать явным образом для очисткиэто вверх (так, например, когда ob2 уничтожается, все его переменные-члены, включая day, уничтожаются).Если вы создаете что-то динамически, вам нужно убедиться, что оно будет уничтожено, когда вы закончите с этим;Рекомендуется использовать так называемый «умный указатель», чтобы эта очистка выполнялась автоматически.

11 голосов
/ 27 октября 2010

Вам не нужно явно вызывать деструктор. Это делается автоматически в конце области видимости объекта ob2, т.е. в конце функции main.

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

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

Поскольку ручное управление памятью подвержено утечкам, современный код C ++ старается вообще не использовать new и delete. Когда действительно необходимо использовать new, тогда вместо обычного указателя используется так называемый «умный указатель».

4 голосов
/ 27 октября 2010

Вы не должны вызывать деструктор явно.

Когда вы создаете свой объект в стеке (как вы это сделали), все, что вам нужно:

int main()
{
  date ob2(12);
  // ob2.day holds 12
  return 0; // ob2's destructor will get called here, after which it's memory is freed
}

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

int main()
{
  date* ob2 = new date(12);
  // ob2->day holds 12
  delete ob2; // ob2's destructor will get called here, after which it's memory is freed
  return 0;   // ob2 is invalid at this point.
}

(Сбой при вызове delete в последнем примере приведет к потере памяти.)

Оба способа имеют свои преимущества и недостатки.Способ стека ОЧЕНЬ быстрый с выделением памяти, которую займет объект, и вам не нужно явно удалять его, но у стека ограниченное пространство, и вы не можете перемещать эти объекты легко, быстро и чисто.

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

3 голосов
/ 27 октября 2010

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

struct test {
   test( int value ) : value( value ) {}
   ~test() { std::cout << "~test: " << value << std::endl; }
   int value;
};
int main()
{
   test t(1);
   test *d = new t(2);
   delete d;           // prints: ~test: 2
}                      // prints: ~test: 1 (t falls out of scope)
* 1005.* Для полноты (это не следует использовать в общем) синтаксис для вызова деструктора аналогичен методу.После запуска деструктора память больше не является объектом этого типа (должен обрабатываться как необработанная память):
int main()
{
   test t( 1 );
   t.~test();            // prints: ~test: 1
                         // after this instruction 't' is no longer a 'test' object
   new (&t) test(2);     // recreate a new test object in place
}                        // test falls out of scope, prints: ~test: 2

Примечание: после вызова деструктора на t эта ячейка памяти небольше test, что является причиной восстановления объекта посредством размещения new .

0 голосов
/ 27 октября 2010

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

Поэтому, как только вы запустите деструктор, у компилятора больше не будет никаких обязательств в отношении этого объекта.Если вы не обращаетесь к нему снова, это не имеет значения.Если вы ссылаетесь на него, это неопределенное поведение, и с точки зрения Стандарта поведение не имеет значения, и, поскольку Стандарт ничего не говорит, большинство разработчиков компиляторов не будут беспокоиться о том, что делает программа.

Вв этом случае проще всего оставить объект нетронутым, поскольку он не удерживает ресурсы, а его хранилище было выделено как часть запуска функции и не будет возвращено до выхода из функции.Следовательно, значение элемента данных останется прежним.При чтении ob2.day компилятору обычно нужно получить доступ к области памяти.

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

0 голосов
/ 27 октября 2010

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

Деструктор - это то, что автоматически вызывается, когда ваш объект выходит из области видимости, то есть когда компьютер оставляет «фигурные скобки», в которых вы создали экземпляр своего объекта. В этом случае, когда вы выходите из main (). Вы не хотите называть это сами.

0 голосов
/ 27 октября 2010

В этом случае вашему деструктору не нужно удалять переменную дня.

Вам нужно вызывать delete только в той памяти, которая была выделена новой.

Вот как будет выглядеть ваш код, если вы используете new и delete для запуска вызова деструктора

class date {

  public: int* day; 
  date(int m) { 
      day = new int;
      *day = m; 
  }

  ~date(){ 
      delete day;
      cout << "now the destructor get's called explicitly";
  } 
};

int main() { 
  date *ob2 = new date(12); 
  delete ob2;
  return 0; 
}
...