【问题标题】:QVector memory managmentQVector 内存管理
【发布时间】:2014-01-08 09:49:34
【问题描述】:

我有一个非常简单的虚拟程序

levenshteindb.h:

#ifndef LEVENSHTEINDB_H
#define LEVENSHTEINDB_H

#include <QVector>
#include "levenshteindbnode.h"

class LevenshteinDB
{
    unsigned size;
    QVector<LevenshteinDBNode> nodes;
    void realloc_rows(unsigned node);

public:
    LevenshteinDB();
    ~LevenshteinDB();
    void add_word();
};

#endif // LEVENSHTEINDB_H

levenshteindb.cpp:

#include "levenshteindb.h"
#include <cstring>
#include <cstdio>    

LevenshteinDB::LevenshteinDB()
{
    size=15;
    nodes.append(LevenshteinDBNode(size));
}

LevenshteinDB::~LevenshteinDB()
{
}


void LevenshteinDB::add_word()
{
    nodes.append(LevenshteinDBNode(size));
}


void LevenshteinDB::realloc_rows(unsigned newsize)
{
    for(unsigned i=0;i<nodes.size();i++)
        nodes[i].realloc(newsize);
}

levenshteindbnode.h:

#ifndef LEVENSHTEINDBNODE_H
#define LEVENSHTEINDBNODE_H

struct LevenshteinDBNode
{
    LevenshteinDBNode();
    LevenshteinDBNode(unsigned size);
    ~LevenshteinDBNode();
    unsigned *row;
    void realloc(unsigned newsize);
};

#endif // LEVENSHTEINDBNODE_H

levenshteindbnode.cpp:

#include "levenshteindbnode.h"

LevenshteinDBNode::LevenshteinDBNode(){};

LevenshteinDBNode::LevenshteinDBNode(unsigned size)
{
    row = new unsigned[size];
}

LevenshteinDBNode::~LevenshteinDBNode()
{
    delete[] row;
}

void LevenshteinDBNode::realloc(unsigned newsize)
{
    delete[] row;
    row=new unsigned[newsize];
}

main.cpp:

#include "levenshteindb.h"

int main()
{
    LevenshteinDB *trie = new LevenshteinDB();
    trie->add_word();
    trie->add_word();
    trie->add_word();
    delete trie;
}

崩溃并且似乎有一个巨大的(与程序本身分配的内存相比)内存泄漏,但我真的不明白出了什么问题.. 我正在使用 qt 5.2

【问题讨论】:

    标签: c++ qt memory qvector


    【解决方案1】:

    你需要阅读the rule of three

    当你这样做时发生了什么

    nodes.append(LevenshteinDBNode(size));
    

    您创建了一个 临时 LevenshteinDBNode objectm,然后复制,导致两个对象具有两个指向同一内存的指针。然后销毁临时对象,这会导致您的析构函数被调用,并删除您分配的内存。现在您有了对象的副本,其中包含指向已删除内存的指针。

    您需要实现一个复制构造函数,它对分配的内存进行所谓的深拷贝。


    您的代码中还有一个更微妙的错误,因为您没有在LevenshteinDBNode 默认构造函数中初始化指针。这意味着如果您有一个默认构造的实例,则指针将具有不确定的值,实际上它将指向一个随机位置。如果在您尝试 delete 这个随机指针时破坏了默认构造的实例,这将导致未定义的行为。需要在默认构造函数中初始化指向nullptr的指针。

    【讨论】:

    • 感谢您的回答,这肯定会解决问题,我还有一件事想问,我应该怎么做才能解决这个问题?我的意思是,我可以为 LevenshteinDBNode 定义一个复制构造函数来制作对象的深层副本,但是这样当我调用“nodes.append(LevenshteinDBNode(size))”时,内存被分配了两次以构造一个看起来对我来说效率不是很高,所以我是否需要创建两个方法 init() 和 free() 来手动分配和释放“行”(并在构造函数和析构函数中擦除任何“新”和“删除”)?
    • @user2318607 不幸的是,它就是这样工作的。如果您有支持 C++11 的编译器(并且 Qt 已更新为使用新的 C++11 功能),您可以使用move semantics 来避免在某些情况下进行复制。但是您仍然需要创建一个复制构造函数来进行第二次分配和数据的副本。
    • 我想你也可以将 LevenshteinDBNode::row 定义为 QVector。
    • @user2318607 你应该使用现有的容器实现,它们不会有这些错误,如QListstd::vector
    • 另外,您可以实现写时复制,例如使用 QSharedDataPointer。
    猜你喜欢
    • 1970-01-01
    • 2018-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-21
    • 2012-03-21
    相关资源
    最近更新 更多