C ++ Destructor вызвал не тот объект?

Graphviz отлично справляется с рисованием стрелок и автопилот. (Нетривиально реализовать в Matplotlib). Вот пример:

import networkx as nx
import matplotlib.pyplot as plt

G = nx.DiGraph()
G.add_edges_from(\[(0,1), (0,2), (1,1), (1,2)\])
nx.write_dot(G,'graph.dot')

# then run dot -Tpng graph.dot > graph.png

enter image description here [/g0]

0
задан Samueljh1 16 January 2019 в 18:57
поделиться

2 ответа

Test x = Test(1);

Это создает новый объект со значением «1».

x = Test(2);

Сначала создается новый объект со значением «2», после чего он будет присвоен первому объекту с оператором присваивания, который неявно создан для вашего класса! В этот момент у вас есть два объекта, каждый из которых имеет значение 2!

Чтобы получить лучшее представление, вы можете сделать это:

class Test{
    public:
        static int instanceCount;
        int id;
        int count;

        explicit Test(int id) : id{id}, count{instanceCount++} {
            std::cout << "Created " << id << " " << count << std::endl;
        }

        ~Test() {
            std::cout << "Destroyed " << id << " " << count << std::endl;
        }

        //Test& operator=(const Test&) = delete;
        Test& operator=(const Test& ex) 
        {
            id=ex.id;
            return *this;
        }
};  


int Test::instanceCount = 0;

int main() {
    Test x = Test{1};
    x = Test{2};

    std::cout << x.id << std::endl; 
    return 0;
}  

Теперь вы можете видеть, когда новый экземпляр создано. Если вы удалите оператор присваивания для своего класса, вы увидите, что первая написанная вами инструкция «Test x = Test {1};» это не задание, а конструкция. Второй "x = Test {2};" потерпит неудачу, так как вы удалили оператора сейчас.

Вывод выглядит следующим образом:

Created 1 0
Created 2 1
Destroyed 2 1
2
Destroyed 2 0

Как видите, вы получаете первый экземпляр с счетчиком 0 и вашим значением 1. Второй временный экземпляр создается как счетчик 1 с вашим значением 2 Затем этот будет назначен первому, а временный экземпляр будет удален до того, как произойдет ваш std :: cout! В тот момент, когда вы покинете область действия основной функции, первый экземпляр будет удален!

Что вы можете узнать:

  • создание объекта с помощью X x=X(3); аналогично записи X x(3);
  • , если вы не написали оператор присваивания вручную, вы можете получить оператор по умолчанию, в зависимости от некоторых других правил (для более широкого здесь).
  • вы должны видеть, что здесь вы создаете временные объекты, которые будут создаваться и удаляться «на лету», но при этом иметь стоимость, которой в большинстве случаев можно избежать!
  • вам следует не [ 119] используйте using namespace std!
  • вы должны написать X x{3} instead of X x (3) `
  • написание X x=X(3); полностью сбивает с толку, так как похоже, что вы создаете временное и затем назначаете это по умолчанию построен один. Но этого не произойдет, и поэтому вы должны написать свой код проще!
0
ответ дан Klaus 16 January 2019 в 18:57
поделиться

Используя отладчик, Created 2 и Destroyed 2 оба отображаются, когда строка x = Test (2); называется. Если мы просто присвоили x объекту 2, почему его деструктор вызывается немедленно? Это следует к следующей части.

Строка x = Test(2); сначала создает Test с аргументом конструктора 2. Это то, что производит Created 2. Этот безымянный Test затем присваивается x, что дает x.id значение 2. Этот безымянный Test затем уничтожается в конце выражения, создавая «Уничтожено 2».

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

Как указано в первой части этого ответа, уничтожается не x, а временно Temp. x.id все еще действует и выдаст новое значение, 2.

Наконец, выводится Destroyed 2. Это имело бы смысл, если бы мы не видели это раньше. Объект 2 хранится в x, поэтому, когда он выходит из области видимости, вызывается деструктор.

Это происходит, когда x уничтожается в конце функции. Это значение id было изменено на 2 предыдущим присваиванием, поэтому оно выдает «Уничтожено 2».

1: Почему происходит это странное поведение, и есть ли логическая причина, почему это так?

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

2: приводит ли «переопределение» объекта (например, объекта 1) к другому объекту (объекту 2) посредством присваивания к его деструктору (в данном случае деструктору объекта 1) для вызова или нет? ]

Присвоение объекту не разрушает его. Он заменяет его значение новым и в этом смысле «уничтожает» значение , которое ему ранее помогало, но фактический экземпляр объекта не уничтожается, а деструктор не участвует.

Редактировать: Возможно, вас беспокоит утечка ресурсов. Так как Test не управляет никакими ресурсами, утечек не будет, и сгенерированные компилятором члены будут вести себя нормально. Если ваш класс действительно управляет ресурсами (обычно в форме динамически выделяемой памяти), то вам нужно будет применить правило 3/5/0 . В частности, вам нужно будет самостоятельно реализовать оператор присваивания, чтобы он очищал любые ранее удерживаемые ресурсы. Недостаточно реализовать только деструктор, поскольку он не участвует в назначении.

0
ответ дан François Andrieux 16 January 2019 в 18:57
поделиться
Другие вопросы по тегам:

Похожие вопросы: