Вопрос:
У меня есть программа на C++, использующая std::shared_ptr
и std::weak_ptr
и включающая два класса: A
и B
. Программа создает общие указатели для обоих классов и устанавливает связь между ними, при этом A
удерживает слабый указатель на B
и B
удерживает общий указатель на A
. Насколько я понимаю, деструкторы должны вызываться в порядке, обратном вызовам стека. Однако выходные данные показывают, что деструктор B
вызывается раньше A
, что мне кажется необычным.
Вот фрагмент кода:
#include <iostream>
#include <memory>
class B;
class A {
public:
std::weak_ptr<B> b_weak_ptr;
~A() {
std::cout << "A destructor called" << std::endl;
}
};
class B {
public:
std::shared_ptr<A> a_ptr;
~B() {
std::cout << "B destructor called" << std::endl;
}
};
int main() {
{
std::shared_ptr<B> b = std::make_shared<B>();
std::shared_ptr<A> a = std::make_shared<A>();
a->b_weak_ptr = b;
b->a_ptr = a;
}
return 0;
}
Выход:
B destructor called
A destructor called
Может ли кто-нибудь объяснить, почему деструктор B
вызывается раньше деструктора A
?
Первоначально я подозревал, что оптимизация компилятора может повлиять на порядок вызовов деструктора, но проверки показали обратное.
a
уничтожается первым, но это только уменьшает количество ссылок на экземпляр A
на одну. В b.a_ptr
все еще есть одна ссылка на него, поэтому экземпляр A
не уничтожается. Когда b
позже уничтожается (и a_ptr
вместе с ним), счетчик ссылок на экземпляр A
становится нулевым, и затем вызывается деструктор A
.
Небольшая модификация вашего кода, чтобы показать его более четко:
int main() {
std::shared_ptr<B> b = std::make_shared<B>();
{
std::shared_ptr<A> a = std::make_shared<A>();
a->b_weak_ptr = b;
b->a_ptr = a;
std::cout << b->a_ptr.use_count() << '\n'; // prints 2
} // a is destroyed
std::cout << b->a_ptr.use_count() << '\n'; // prints 1
} // b is destroyed
Выход:
2
1
B destructor called
A destructor called