2

我创建了实现指向结构的指针数组的类...我知道如何将记录添加到这个数组,但我不知道如何正确删除它们,因此我有内存泄漏。我的数组的大小在需要时会增加,我知道数组的大小以及那里有多少记录。我习惯于用具有垃圾收集器的语言进行编码,所以这对我来说很困惑。如果你们中的任何人能告诉我如何正确释放该数组,我会很高兴。

请注意,我不能使用vector. 我仅限于包括以下内容:

#include <iostream>
#include <iomanip>
#include <string>
#include <cstring>
#include <cstdlib>
#include <cstdio>

我的代码:

struct DbRecord
{
    string oName;
    string oAddr;
    string cName;
    string cAddr;
};

class CCompanyIndex
{
    public: CCompanyIndex(void);~CCompanyIndex(void);
    bool Add(const string & oName,
    const string & oAddr,
    const string & cName,
    const string & cAddr);
    bool Del(const string & oName,
    const string & oAddr);
    bool Search(const string & oName,
    const string & oAddr,
    string & cName,
    string & cAddr) const;

    int size;
    int position;
    DbRecord * * db;
};

CCompanyIndex::CCompanyIndex(void)
{
    db = new DbRecord * [1000];

    size = 1000;
    position = 0;
}

CCompanyIndex::~CCompanyIndex(void)
{
}

int main(int argc, char const * argv[])
{

    CCompanyIndex c1;
    // do something..with c1, i.e. add there some records to array
    // ...
    // ...
    // delete it now
}
4

4 回答 4

1

经验法则是在析构函数中反转构造函数中与内存管理相关的操作。也就是说,既然你db = new DbRecord * [1000];在构造函数中有,你应该delete[] db;在析构函数中有 a 。

但是请注意,您很可能在这里不需要动态内存管理(使用按值语义),并且您可能希望研究 C++ 提供的更高级别的抽象,例如vector类 - 就像 AndyProwl 和 JamesKanze 建议的那样。

于 2013-03-31T13:36:01.777 回答
1

用于std::vector避免必须通过原始指针、new[]和手动管理内存delete[]。这样做(正如您所经历的那样)容易出错,并且很容易导致内存泄漏或未定义的行为。

DbRecord出于同样的原因,我还建议使用智能指针而不是原始指针来保存对对象的引用。您应该根据所需的所有权策略选择您的智能指针。在这里,我会假设std::shared_ptr是合适的。

但是请注意,如果您不需要引用语义,那么您根本不应该使用指针,而是将您的容器声明为std::vector<DbRecord>。在这里,我假设您确实需要引用语义,因为您的原始版本使用(原始)指针;但同样,如果你不这样做,不要使用指针。

因此,鉴于必要的#include指令和using声明:

#include <string>
#include <vector>
#include <memory>

using std::string;
using std::vector;
using std::shared_ptr;

DbRecord以及数据结构的(未更改的)定义:

struct DbRecord {
    string oName;
    string oAddr;
    string cName;
    string cAddr;
};

您可以更改CCompanyIndexthis 的定义(如您所见,用户定义的默认构造函数和析构函数现在是多余的,您可以让编译器隐式生成它们):

class CCompanyIndex {
public:

//  No more need for a user-defined default constructor and destructor!

    bool Add(const string & oName,
            const string & oAddr,
            const string & cName,
            const string & cAddr);
    bool Del(const string & oName,
            const string & oAddr);
    bool Search(const string & oName,
            const string & oAddr,
            string & cName,
            string & cAddr) const;

    std::vector<std::shared_ptr<DbRecord>> db;
//  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
};

最后,请注意您不需要执行任何手动清理:

int main(int argc, char const *argv[])
{
    CCompanyIndex c1;
    // do something..with c1, i.e. add there some records to array
    // ...
    // ...

    // NO NEED TO MANUALLY DELETE IT NOW!
}
于 2013-03-31T13:28:38.470 回答
0

您不应该在这里进行任何内存管理。几乎没有任何理由使用新数组;只需使用 std::vector. 而且真的没有理由动态分配你的DbRecord; 因为它具有值语义:

std::vector<DbRecord> db;

做得很好。

于 2013-03-31T13:31:34.880 回答
0

您可以使用运算符deletedelete[]释放内存。例如,您可以在析构函数中释放内存,如下所示:

CCompanyIndex::~CCompanyIndex(void)
{
  // delete objects pointed-to in a loop. 
  // !! the objects MUST have been allocated, or the pointers MUST be set to null. 
  // note that 'delete' is null-safe. 
  for(DbRecord* it=db; it<db+position; ++it)
  {
    delete *it; 
  }

  // delete the array of pointers
  delete[] db;
}

delete释放为单个对象分配的内存(通过new),而delete[]释放为对象数组分配的内存(通过new[],如您的情况)。

不要重新发明轮子 - 只需使用std::vector<DbRecord*>. 它为您进行内存管理,您的代码将更简单、更易读。C++ 提供了强大的标准库,让大多数程序员甚至不需要使用手动内存管理。

于 2013-03-31T13:35:44.133 回答