unique_ptr 的多个实例

mrg*_*g95 0 c++ qt class smart-pointers

在发现我需要我创建的delete任何new指针后,我很快意识到我的项目充满了内存泄漏,而我什至不知道。所以提示我使用智能指针。但是,在尝试创建智能指针的多个实例时,我遇到了问题。我创建了一个 SSCE 来更好地解释这一点。

主窗口.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <memory>
#include "classa.h"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private slots:
    void on_pushButton_clicked();

private:
    Ui::MainWindow *ui;
    std::unique_ptr<ClassA> classa; //<----- a smart pointer of a Class type
};

#endif // MAINWINDOW_H
Run Code Online (Sandbox Code Playgroud)

主窗口.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "classa.h"
#include <QDebug>

QVector<ClassA*> classes;//<------ QVector that contains instances of ClassA
                                    //So I can retrieve them later based on an index.

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    classa = std::unique_ptr<ClassA>(new ClassA()); //<---- Created here
    classes.push_back(classa.get()); //<---- appended to the QVector
}

MainWindow::~MainWindow()
{
    delete ui;
}

//When the button is clicked, the program crashes when trying to qDebug
//because the first instance that was loaded in the QVector is no longer
//"valid." It stops being "valid" when I create the second instance of ClassA
void MainWindow::on_pushButton_clicked()
{
    classa = std::unique_ptr<ClassA>(new ClassA());
    classes.push_back(classa.get());

    qDebug() << classes.at(0);
}
Run Code Online (Sandbox Code Playgroud)

希望以上评论足以解释。我想到的第一个解决方案是将 mainwindow.h 中的声明更改为,std::unique_ptr<ClassA> *classa;但这不会违背智能指针的目的吗?

真的很困惑。谢谢你的时间。

Dev*_*lar 5

我认为您困惑的核心在于std::unique_ptr<>实际做了什么。

从您的 MainWindow 构造函数中:

classa = std::unique_ptr<ClassA>(new ClassA());
Run Code Online (Sandbox Code Playgroud)

classa现在(聪明地)指向ClassA实例#1。如果该内存引用超出范围,该内存将被删除,从而避免内存泄漏。

classes.push_back(classa.get());
Run Code Online (Sandbox Code Playgroud)

classes[0]现在持有一个指向实例 #1 的(哑)指针。

从您的按钮单击事件处理程序:

classa = std::unique_ptr<ClassA>(new ClassA());
Run Code Online (Sandbox Code Playgroud)

classa现在(聪明地)指向ClassA实例#2。

通过为 分配一个新值classa,旧值超出了范围。为实例 #1 分配的内存现已释放。这就是智能指针的目的。

classes[0]仍然保存着一个(哑)指针,指向先前由实例 #0 保存的内存 。(你知道这是怎么回事,不是吗?)

classes.push_back(classa.get());
Run Code Online (Sandbox Code Playgroud)

classes[1]现在持有一个指向实例 #2 的(哑)指针。

qDebug() << classes.at(0);
Run Code Online (Sandbox Code Playgroud)

未定义的行为,你就会死。


如果你的内存由智能指针管理——正如你应该的那样——让它由智能指针管理。不要将.get()愚蠢的指针移出它们并将它们存储在其他地方。


由于您的示例没有告诉我们classes向量应该用来做什么,因此此时很难给出正确的建议。

  • 您可以直接使用vector< ClassA >来存储实例ClassA
  • 您可以用来vector< std::shared_ptr< ClassA > >存储智能指针,可以在其他地方使用它们。(*)

或者...

  • 您可以告诉我们您想要解决的实际问题,我们可以告诉您最好的容器是什么。;-)

(*):

std::shared_ptr<>是更强大的兄弟姐妹std::unique_ptr<>。唯一指针是唯一的,无法复制。从好的方面来说,它们与您手动操作的“普通”指针一样高效delete

std::shared_ptr<>添加一点点簿记,即存在的副本数量(因为它可以复制),并且仅在智能指针的最后一个副本超出范围时才删除内存。

要么依赖于您存储(和使用)它们包含的指针。