Подтвердить что ты не робот

С++ - деструктор, вызываемый дважды

Я экспериментировал с деструкторами в С++ с этим фрагментом кода:

#include <iostream>

struct temp
{
    ~temp() { std::cout << "Hello!" << std::endl; }
};

int main()
{
    temp t;
    t.~temp();
}

Я вижу, что "Привет!" печатается дважды. Не следует ли снова вызывать вызов деструктора объекту и деструктору, когда он выходит за рамки? Или есть какая-то другая концепция?

(Я не собираюсь делать это на практике. Я просто пытаюсь понять, что происходит здесь.)

4b9b3361

Ответ 1

Это происходит потому, что вы сказали, что это произойдет. Деструктор для автоматической переменной всегда вызывается, когда переменная выходит за пределы области видимости. Вы также назвали это. Всего два вызова.

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

Решение состоит в том, чтобы никогда не вручную вызывать деструктор.

Ответ 2

Вызов деструктора не освобождает объект.

Деструктор предназначен для очистки внутренних объектов объекта, а затем сам объект освобождается после завершения деструктора.

Это ошибка для того, что вы делаете аналогично тому, как вы можете дважды вызвать удаление объекта, но это ошибка для этого.

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

Ответ 3

Я вижу, что "Привет!" печатается дважды. не следует ли вызывать вызов деструктора объекту, а деструктор не следует вызывать снова, когда он выходит за пределы области видимости. Или есть какая-то другая концепция?

Это правильно.

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

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

То, что нужно понять, таково: если вы делаете то, что не имеет смысла, тогда происходят плохие вещи. Поэтому не делайте то, что не имеет смысла. Если вы вручную вызовите деструктор, выполняется дескриптор. Это не влияет ни на что другое, если деструктор фактически не делает что-то, что имеет эффект.

Ответ 4

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

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

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

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

class A
{
public:
    A() : _closed(false)
    {}

    ~A()
    {
        close();
    }

    void close()
    {
        if (! _closed()) {
            // close file handles etc.
        }
    }

private:
    bool _closed
}

Ответ 5

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

Ответ 6

Деструктор не является "разрушителем" объекта. Это просто обычная функция, но она автоматически называется языком непосредственно перед временем разрушения.

Это официальное название - деструктор, но, возможно, это было бы легче понять, если бы мы назвали его функцией "Before-Destruction".

Ответ 7

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

Ответ 8

На самом деле вы не должны называть деконструктор. Он называется для вас поддержкой времени выполнения. Следовательно, вы вызываете его один раз, а поддержка времени выполнения вызывает его во второй раз.

Вот немного пищи для размышлений о деструкторах:

http://publib.boulder.ibm.com/infocenter/comphelp/v8v101/index.jsp?topic=%2Fcom.ibm.xlcpp8a.doc%2Flanguage%2Fref%2Fcplr380.htm

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

Ответ 9

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

Если вы хотите, чтобы удалить экземпляр этого класса самостоятельно, явным образом вам необходимо динамически его выделить:

temp *t = new temp;     
// do stuff with t...
delete t;    // do not forget this, or the constructor is not being called at all

Ответ 10

Можно вызвать деструктор класса:

  • Явное

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

  • Косвенно

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

В вашей примерной программе вы выполняете обе функции

int main()
{
  temp t;

  t.~temp(); //1. Calling destructor explictly using the object `t`

  return 0;
} // 2. object `t` goes out of scope. So destructor invoked implictly

и именно поэтому вы видите деструктор, вызываемый дважды.

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