многопоточность — как очистить память от удаленного объекта в c ++?

Я хочу разработать свою собственную область сигнала на C ++. Поэтому я использую qt для этой цели.
Я добавляю graphicsView и кнопку в пользовательском интерфейсе. При подключенном методе к кнопке я обновляю graphicsView (наконец, я передам этот метод потоку).
Каждый раз, когда я нажимаю кнопку, несмотря на удаление указателя, использование памяти увеличивается. Как мне это контролировать?

Я проверяю использование памяти в инструменте диагностики vs15.

заголовочный файл c ++:

#pragma once

#include <QtWidgets/QMainWindow>
#include "ui_QtGuiApplication.h"#include <QGraphicsScene>
#include <QGraphicsPathItem>
class QtGuiApplication : public QMainWindow
{
Q_OBJECT

public:
QtGuiApplication(QWidget *parent = Q_NULLPTR);

private:
Ui::QtGuiApplicationClass ui;

QGraphicsScene* scene = new QGraphicsScene();
QPolygon pol;
QGraphicsPathItem* pathItem = new QGraphicsPathItem();
int index_ = 0;            // graph offset
QPen* myPen = new QPen(Qt::red, 2);

private slots:
void btn_Display_clicked();
};

исходный файл c ++:

    #include "QtGuiApplication.h"#include <math.h>       /* sin */

#define pi 3.14159265

QtGuiApplication::QtGuiApplication(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
ui.graphicsView->setScene(scene);
ui.graphicsView->show();
connect(ui.btn_Display, SIGNAL(clicked()), this, SLOT(btn_Display_clicked()));
}

void QtGuiApplication::btn_Display_clicked()
{
scene->removeItem(pathItem);
QPoint pos;

double x_amp_, y_amp_;
int x_pix_, y_pix_;
double phi_ = 0;
double freq_ = 5;
for (int i = 0; i<800; i++)
{
y_amp_ = 100 * sin(2 * pi*freq_*i / 811 + phi_) + 20 * index_;
x_amp_ = i;
x_pix_ = x_amp_;
y_pix_ = y_amp_;
pos.setX(x_pix_);
pos.setY(y_pix_);
pol.append(pos);
}
QPainterPath* myPath = new QPainterPath();
(*myPath).addPolygon(pol);
pathItem = scene->addPath(*myPath, *myPen);
delete myPath;
pol.clear();
index_ = (index_ + 1) % 20; // just for sense of change in graph
}

0

Решение

У меня есть несколько комментариев.

  1. Вы делаете много совершенно ненужного ручного управления памятью. Почему это плохо? Потому что, если бы ты не был, твоя ошибка была бы невозможна по построению. Все ваше использование ручного выделения памяти (явное new) не нужны. Храните объекты по значению: они были разработаны для такой работы, и пусть компилятор беспокоится обо всем остальном.

  2. Вы объявляете объекты в слишком больших областях. Вы объявляете полигон и перо в классе, даже если они принадлежат области видимости. btn_Display_clicked; вы объявляете переменные цикла (x_amp_ а также y_amp_) за пределами цикла.

  3. connect утверждение излишне: setupUi делает связь для вас.

  4. Вы не полностью используете C ++ 11.

  5. Включает в себя формы <QtModule/QClass> отложить обнаружение неверной конфигурации проекта до времени ссылки и не нужно. Вы должны включить <QClass> непосредственно. Если вы получили ошибку компиляции, значит ваш проект неправильно настроен — возможно, вам нужно перезапустить qmake (типичное решение).

  6. В C ++ <cmath> идиоматично, а не <math.h>, Последний сохраняется для совместимости с C.

  7. Возможно, вы захотите использовать M_PI, Это широко используемое имя для пи в C ++.

  8. Предварительное выделение многоугольника позволяет избежать преждевременной пессимизации перераспределения хранилища точек по мере его роста.

  9. Вы теряете точность, используя целочисленный многоугольник, если только этот выбор не сделан по определенной причине. В противном случае вы должны использовать QPolygonF,

Таким образом, интерфейс становится:

#pragma once

#include <QMainWindow>
#include <QGraphicsScene>
#include <QGraphicsPathItem>
#include "ui_QtGuiApplication.h"
class GuiApplication : public QMainWindow
{
Q_OBJECT

public:
GuiApplication(QWidget *parent = {});

private:
Ui::GuiApplicationClass ui;

QGraphicsScene scene;
QGraphicsPathItem pathItem; // the order matters: must be declared after the scene
int index_ = 0;

Q_SLOT void btn_Display_clicked();
};

И реализация:

#include "GuiApplication.h"#define _USE_MATH_DEFINES
#include <cmath>

#if !defined(M_PI)
#define M_PI (3.14159265358979323846)
#endif

GuiApplication::GuiApplication(QWidget *parent) : QMainWindow(parent)
{
ui.setupUi(this);
ui.graphicsView->setScene(&scene);
ui.graphicsView->show();
pathItem.setPen({Qt::red, 2});
scene.addItem(&pathItem);
}

void GuiApplication::btn_Display_clicked()
{
const double phi_ = 0;
const double freq_ = 5;
const int N = 800;
QPolygonF pol{N};
for (int i = 0; i < pol.size(); ++i) {
qreal x = i;
qreal y = 100 * sin(2 * M_PI * freq_ * i / 811 + phi_) + 20 * index_;
pol[i] = {x, y};
}
QPainterPath path;
path.addPolygon(pol);
pathItem.setPath(path);
index_ = (index_ + 1) % 20; // just for sense of change in graph
}

В C ++ 14 вы можете легко выделить генератор, если хотите использовать его в другом месте; тогда цикл будет заменен на:

auto generator = [=,i=-1]() mutable {
++i;
return QPointF{qreal(i), 100 * sin(2 * M_PI * freq_ * i / 811 + phi_) + 20 * index_};
};
std::generate(pol.begin(), pol.end(), generator);

Увы, в нынешнем виде btn_Display_clicked Реализация отбрасывает кучу, выделенную для хранения многоугольника, и излишне копирует данные из многоугольника во внутреннее хранилище элементов в пути. Мы можем избежать и того и другого, напрямую изменяя путь элемента рисования:

void GuiApplication::btn_Display_clicked()
{
const double phi_ = 0;
const double freq_ = 5;
const int N = 800;
if (pathItem.path().isEmpty()) { // preallocate the path
QPainterPath path;
path.addPolygon(QPolygon{N});
pathItem.setPath(path);
}
auto path = pathItem.path();
pathItem.setPath({}); // we own the path now - item's path is detached
Q_ASSERT(path.elementCount() == N);
for (int i = 0; i < path.elementCount(); ++i) {
qreal x = i;
qreal y = 100 * sin(2 * M_PI * freq_ * i / 811 + phi_) + 20 * index_;
path.setElementPositionAt(i, x, y);
}
pathItem.setPath(path);
index_ = (index_ + 1) % 20; // just for sense of change in graph
}

Так как QPainterPath является неявно разделяемым классом значений, path = item.path(); item.setPath({}); последовательность эквивалентна перемещению пути из элемента пути. Последующее setPath(path) перемещает его назад, так как мы не делаем дальнейших изменений в локальной копии.

2

Другие решения

В

pathItem = scene->addPath(*myPath, *myPen);

Новый QGraphicsPathItem был создан и указатель возвращен pathItem, Рано или поздно кнопка нажимается снова и

scene->removeItem(pathItem);

удаляет QGraphicsPathItem со сцены. к несчастью согласно документации

Право собственности на элемент передается вызывающей стороне (то есть QGraphicsScene больше не будет удалять элемент при уничтожении).

Удаление pathItem зависит от программиста. pathItem не удаляется и просачивается при последующем вызове

pathItem = scene->addPath(*myPath, *myPen);

Решение: Удалить pathItem до того, как это просочится.

scene->removeItem(pathItem);
delete pathItem;

должен сделать работу.

3

По вопросам рекламы [email protected]