#c #qt #memory-leaks #smart-pointers
#c #qt #утечки памяти #интеллектуальные указатели
Вопрос:
#include <QScopedArrayPointer>
#include <QDebug>
#include <stdexcept>
class MyData{
public:
MyData() {
qDebug() << "Construct a data";
}
~MyData() {
qDebug() << "Delete a data";
}
private:
float internal_data_;
};
class MyClass{
QScopedArrayPointer<MyData> data_;
public:
MyClass(){
data_.reset(new MyData[10]);
throw std::runtime_error("Shit happens");
}
};
int main(int argc, char *argv[])
{
MyClass a_class;
return 1;
}
Запуск этой программы приведет к:
Construct a data
Construct a data
Construct a data
Construct a data
Construct a data
Construct a data
Construct a data
Construct a data
Construct a data
Construct a data
terminate called after throwing an instance of 'std::runtime_error'
what(): Shit happens
The program has unexpectedly finished.
Прямо перед runtime_error переменная data_ была полностью создана. Почему не вызывается data_ destructor?
Кроме того, как мне убедиться, что в этом случае не происходит утечки памяти?
Комментарии:
1. Чего вы ожидаете? Деструктор не вызывается, потому что
std::runtime_error
не перехватывается.2. Я надеялся, что, поскольку построение data_ завершено, его деструктор будет вызван автоматически. Как мне убедиться, что выделенные данные освобождаются при возникновении исключения?
3. Если вы создадите конкретное исключение из конструктора, ваш ограниченный массив все еще может содержать ссылку. В идеале вы хотели бы перехватить это исключение и обработать его, а не разворачивать до прерывания.
4. На самом деле мой первый комментарий был неправильным, извините. Проблема в том, что вы создаете из конструктора. Когда вы создаете объект из конструктора, объект не полностью сконструирован, поэтому его деструктор не будет вызван.
Ответ №1:
Я думаю, проблема в том, что ваше исключение не перехвачено и обрабатывается обработчиком terminate. Поскольку нет catch
способа обработать исключение, компилятор не может узнать, сколько нужно «развернуть». Если вы перехватываете исключение, происходит уничтожение. Затем вы, конечно, можете повторно запустить его, если хотите, например:
#include <QScopedArrayPointer>
#include <QDebug>
#include <stdexcept>
class MyData{
public:
MyData() {
qDebug() << "Construct a data";
}
~MyData() {
qDebug() << "Delete a data";
}
private:
float internal_data_;
};
class MyClass{
QScopedArrayPointer<MyData> data_;
public:
MyClass(){
data_.reset(new MyData[10]);
throw std::runtime_error("Shit happens");
}
};
int main(int argc, char *argv[]) {
try {
MyClass a_class;
} catch (const std::runtime_error amp;) {
throw;
}
}
Выводит следующее:
$ ./test2
Construct a data
Construct a data
Construct a data
Construct a data
Construct a data
Construct a data
Construct a data
Construct a data
Construct a data
Construct a data
Delete a data
Delete a data
Delete a data
Delete a data
Delete a data
Delete a data
Delete a data
Delete a data
Delete a data
Delete a data
terminate called after throwing an instance of 'std::runtime_error'
what(): Shit happens
Aborted