Почему std :: shared_ptr уничтожается дважды при использовании std :: static_pointer_cast? - PullRequest
0 голосов
/ 23 февраля 2020

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

#include <iostream>
#include <memory>
#include <vector>
using namespace std;


struct A {
    A() { cout << "c"; }
    ~A() { cout << "d"; }
};

int main() {
    shared_ptr<void> a = make_shared<vector<A>>(3);
    auto b = static_pointer_cast<vector<A>>(a);
    b->push_back(A{});
    return 0;
}

Он печатает:

ccccdddddddd

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

Ответы [ 2 ]

2 голосов
/ 23 февраля 2020

Исправлять нечего. Деструктор не вызывается дважды на объект. Скорее, вы не отслеживаете все конструкторы. Добавьте отслеживание к конструкторам копирования и перемещения, как в

struct A {
    A() { cout << "c"; }
    A(const A &) { cout << "C"; }
    A(A &&) { cout << "M"; }
    ~A() { cout << "d"; }
};

. С этим изменением ваш вывод должен быть

ccccMCCCdddddddd

, указывая 8 вызовов конструктора и 8 вызовов деструктора.

1 голос
/ 23 февраля 2020

Вызовы деструкторов являются результатом b->push_back(A{});, а не static_pointer_cast

#include <iostream>
#include <memory>
#include <vector>
using namespace std;


struct A {
    A() { cout << "c"; }
    ~A() { cout << "d"; }
};

int main() {
    shared_ptr<void> a = make_shared<vector<A>>(3);
    auto b = static_pointer_cast<vector<A>>(a);

    return 0;
}

показывает cccddd.

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

В вашем случае конструкции копирования / перемещения были созданы по умолчанию. Если вы определите их вручную и добавите в них протоколирование, вы увидите, что они совпадают.

struct A {
    A() { cout << "c"; }
    A(const A&)  { cout << "C"; };
    A(A&&)  { cout << "M"; };
    ~A() { cout << "d"; }
};

Единственный способ предотвратить это - создать вектор с достаточно большой емкостью, чтобы вместить все элементы. что вы хотите сохранить в нем.

...