#c #shared-ptr #weak-ptr
Вопрос:
Я разработал App
устройство, которое содержит стопку layers
и активный obj
. Когда a Layer
присоединен к App
, то Layer
говорит App
, что такое активный object
. Но мой дизайн вызывает sigtrap при освобождении.
Это вызывает sigtrap, потому shared_ptr<Obj> m_obj
что сначала происходит разрушение в приложении, которое уменьшает значение use_count
до 1. Затем onDetech
функция получает вызов, устанавливая активное shared_ptr<Obj> m_obj
значение nullptr
и уменьшая use_count
его до 0! Но тот layer
все еще держится shared_ptr<Obj>
.
Приведенный ниже код является минимальным примером для воспроизведения. Я замечаю, что в моем коде есть ссылочный цикл, но я понятия не имею, как это исправить, кроме как использовать необработанный указатель для obj
в App
классе.
Я использовал shared_ptr
для obj
in App
, потому что для меня имеет смысл, что App
имеет общую собственность obj
. Не следует ли мне использовать shared_ptr
в этом случае?
class App;
class Obj {
public:
~Obj() { std::cout << "obj destruct" << std::endl; }
};
class Layer {
public:
Layer() { m_obj = std::make_shared<Obj>(); }
~Layer() { std::cout << m_obj.use_count() << std::endl; }
void onAttach(App *app);
void onDetach();
std::shared_ptr<Obj> m_obj;
private:
App *m_app;
};
class LayerStack {
public:
void pushLayer(App *app, std::shared_ptr<Layer> layer) {
m_layers.push_back(layer);
layer->onAttach(app);
}
~LayerStack() {
for (auto amp;layer : m_layers) {
layer->onDetach();
}
}
private:
std::vector<std::shared_ptr<Layer>> m_layers;
};
class App {
public:
App() {
m_defaultLayer = std::make_shared<Layer>();
m_stack.pushLayer(this, m_defaultLayer);
}
~App() {}
LayerStack m_stack;
std::shared_ptr<Layer> m_defaultLayer;
std::shared_ptr<Obj> m_activeObj;
};
void Layer::onAttach(App *app) {
m_app = app;
app->m_activeObj = m_obj;
std::cout << m_obj.use_count() << std::endl;
}
void Layer::onDetach() {
m_app->m_activeObj = nullptr;
std::cout << m_obj.use_count() << std::endl;
}
int main() {
A a;
}
выход:
2
obj destruct
-923414512
-923414512
Комментарии:
1. Спасибо за ваше предложение. Я обновил свой пример кода. Но проблема, которую я описал, все еще существует. Значение
use_count
уменьшается до отрицательного.2. Это не уменьшилось до отрицательного, вы просто читаете мусор. Адрес дезинфицирующего средства можно найти там, где вы пользовались после бесплатного: godbolt.org/z/s1YxbsWdc
Ответ №1:
Вы получаете доступ m_activeObj
после истечения срока его действия, и, следовательно, поведение вашей программы не определено.
Последовательность событий выглядит следующим образом:
App
объект выходит за рамки~App
бежитm_activeObj
уничтожается; после этого его срок службы заканчивается, и к нему больше нельзя получить доступm_defaultLayer
уничтожаетсяm_stack
уничтожаетсяm_layers[0].onDetach()
называетсяonDetach
устанавливаетсяm_app->m_activeObj
вnullptr
значение , но его срок службы уже истек, поэтому поведение не определено.
- Неуместные другие вещи; ты уже облажался.
Решение состоит в том, чтобы изменить порядок вещей, чтобы вы не получали доступ m_activeObj
к ним после истечения срока их службы. Либо переместите m_stack
объявление после m_activeObj
, чтобы оно было уничтожено первым, либо очистите его вручную ~App
.
Комментарии:
1. О… хорошо, теперь я это понимаю. Еще один вопрос, почему я не получаю sigfault при ссылке на уничтоженный объект?
2. Потому что неопределенное поведение не определено.