Пример QT Image Viewer, возможная утечка памяти? - PullRequest
0 голосов
/ 13 февраля 2019

A Пример просмотра изображений на веб-сайте документации QT содержит следующий фрагмент кода:

ImageViewer::ImageViewer()
   : imageLabel(new QLabel)
   , scrollArea(new QScrollArea)
   , scaleFactor(1)
{
   imageLabel->setBackgroundRole(QPalette::Base);
   imageLabel->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
   imageLabel->setScaledContents(true);

   scrollArea->setBackgroundRole(QPalette::Dark);
   scrollArea->setWidget(imageLabel);
   scrollArea->setVisible(false);
   setCentralWidget(scrollArea);

   createActions();

   resize(QGuiApplication::primaryScreen()->availableSize() * 3 / 5);
}

Где imageLabel и scrollArea являются указателями на элементы QLabel иQScrollArea соответственно.

Я понимаю, что в строке scrollArea->setWidget(imageLabel); область прокрутки становится владельцем указателя imageLabel и удаляет его при необходимости.Аналогично для setCentralWidget(scrollArea);, где окно становится владельцем области scrollArea.

Однако, во время построения, если создание imageLabel должно было быть успешным, но создание scrollArea не удалось бы, imageLabelне утечка?

Если да, каков канонический способ решить эту проблему?

Ответы [ 2 ]

0 голосов
/ 14 февраля 2019

Решено пока так:

ImageViewer::ImageViewer()
    : scaleFactor(1)
{
   //Manage pointers with unique_ptr until it's time to transfer ownership. 
   auto uniqueImageLabel = std::make_unique<QLabel>();
   auto uniqueScrollArea = std::make_unique<QScrollArea>();

   //Copy pointers to members for access as per normal.
   imageLabel = uniqueImageLabel.get();
   scrollArea = uniqueScrollArea.get(); 

   imageLabel->setBackgroundRole(QPalette::Base);
   imageLabel->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
   imageLabel->setScaledContents(true);

   scrollArea->setBackgroundRole(QPalette::Dark);
   //ScrollArea now takes ownership of image label. 
   scrollArea->setWidget(uniqueImageLabel.release());
   scrollArea->setVisible(false);
   //Window now takes ownership of scroll area.
   setCentralWidget(uniqueScrollArea.release());

   createActions();

   resize(QGuiApplication::primaryScreen()->availableSize() * 3 / 5);
}
0 голосов
/ 13 февраля 2019

Я думаю, что есть два пути:

1 .Используйте умные указатели вместо raw (например, QPointer).

    class ImageViewer : public QMainWindow
    {
       QPointer<QLabel> imageLabel;
       QPointer<QScrollArea> scrollArea;
    };

В этом случае будет вызываться деструктор imageLabel, если конструктор scrollArea (или тело конструктора ImageViewer выдаетисключение)

2 .Переместите выделение памяти внутри тела конструктора и оберните его блоком try / catch.

    ImageViewer::ImageViewer()
        : imageLabel(nullptr)
        , scrollArea(nullptr)
        , scaleFactor(1)
    {
        try {
            imageLabel = new QLabel();
            scrollArea = new QScrollArea();
        } catch (std::bad_alloc&) {
            delete imageLabel;
            delete scrollAreal;
        }
        // ...
    }

Более подробную информацию можно найти здесь ( Мораль # 4 о вашем вопросе)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...