在C ++中如何正确删除循环中动态分配的对象

时间:2013-10-30 21:40:28

标签: c++ pointers memory-management

当我在循环中使用动态分配的对象指针时,我的C ++正规教育的教程,搜索和昏暗内存让我无法理解删除的位置,例如:

// necessary files are included, this code is within main
T * t;
t = foo.getNewT();
while (!t->isFinalT()) {

    // print t stuff

    delete t;         // is this where I should delete t?
    t = foo.getNewT();
}

delete t;

这种缺乏知识在最近的课堂项目中变得特别麻烦。在我的笔记本电脑上(Linux Mint,g ++ Ubuntu / Linaro 4.7.3-1ubuntu1),代码在没有删除语句的情况下运行良好,并在添加delete语句时崩溃。在学校服务器(Solaris,g ++(GCC)3.4.5)上,代码在没有delete语句的几次迭代后进行了分段,并且在添加delete语句时运行正常。

如何正确处理这种循环,以便它能在大多数环境中运行?

其他信息: 当程序到达删除请求时,笔记本电脑上出现错误:

*** Error in 'program': free(): invalid next size (fast): ...

其他一些代码:

// T.h
class T {
    int id;
    int num;
    int strVarPos;
    char * strVar;
  public:
    T();
    ~T();
    // + misc. methods
}

// T.cpp
T::T() {
    id = 0;
    num = -1;
    strVarPos = 0;
    char * strVar = new char[11];
    strVar[0] = '\0'
}

T::~T() {
    delete [] strVar;
}

// Foo.cpp
T * Foo::getNewT() {
    T * t = new T;

    // populate T's fields

    return t;
}

解决:

因为只有T * t的简单测试和循环工作正常,我最终从空白开始重建项目并一次添加一个类,以查看问题何时出现。事实证明,我已将其他内容添加到程序中其他位置的动态分配数组中,而不更新我用于初始化数组的大小常量。

显然学校服务器只能处理由此产生的内存差异而不会崩溃,如果我确保正确删除指针(程序运行时间不足以导致我的测试中出现大量内存泄漏),而我的笔记本电脑不会在我尝试调用删除(然后崩溃)之前,请注意内存不一致。

4 个答案:

答案 0 :(得分:1)

问题不在于delete。你把它放在了正确的地方。你正在做的其他事情更可能导致未定义的行为。

请注意,在循环之后你应该有delete t (赶上最后一个)。这假设foo.getNewT()总是返回一个有效的指针(它必须,因为你永远不会检查它是否为NULL)。

答案 1 :(得分:1)

当您不再需要时,应删除动态分配的内存。如果您希望tfor循环中保留其值,则在循环外删除它,否则将其删除。

但是,最好的办法是在必须使用指针时使用std::unique_ptr。当所有对内存的引用都被破坏时,它将负责释放内存本身。你应该尽量避免分配内存。如果STL容器适合这项工作,请使用它。

答案 2 :(得分:1)

假设foo.getNewT()正在将内存的所有权交给调用者:

T * t;
t = foo.getNewT();
//while (!t->isFinalT()) // if foo.getNewT ever returns NULL, this will be UB!!!
while (t != nullptr && !t->isFinalT()) 
{
    // ...
    delete t; // if you now own it and are no longer going to use it, yes, delete it here
    t = foo.getNewT();
}
delete t; // you also need this one to delete the "final" t

但是,您可以使用std::unique_ptr

来避免自己动手
std::unique_ptr<T> t;
t.reset(foo.getNewT());
while (t && !t->isFinalT()) 
{
    // ...
    t.reset(foo.getNewT());
}

或者,您可以重写循环以更好地流动:

std::unique_ptr<T> t;
do
{
    t.reset(foo.getNewT());
    if (t)
    {
        // do stuff with t
    }
} while (t && !t->isFinalT());
  

代码在没有删除语句的情况下运行正常并在我崩溃时崩溃   添加了删除声明。

确定 getNewT是否正在将T*的所有权交给您?如果删除它,然后尝试稍后删除它,最终会导致堆损坏。如果它将所有权交给调用者,并且您不删除它,则会出现内存泄漏。

使用编辑中的其他信息:

char * strVar = new char[11];

如果您将strVar声明为std::stringchar[11],则不需要该行。如果您尝试复制任何这些T对象,您将使用默认的复制构造函数(因为您还没有定义一个),这将执行浅拷贝(即,复制指针的值为strVar)。当您删除两个指向同一内存位置的T时,会出现堆损坏。最强大的解决方案是将strVar声明为std::string

答案 3 :(得分:0)

我想当你delete t删除结构中的真实对象时。

可能是导致问题的原因。