c++ - 在 C++ 中的循环中正确删除动态分配的对象的位置

标签 c++ pointers memory-management

当我在循环中使用动态分配的对象指针时,教程、搜索和我对 C++ 正规教育的模糊内存让我不知道应该在哪里使用 delete,例如:

// 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 语句的情况下运行良好,但在我添加 delete 语句时崩溃了。在学校服务器(Solaris、g++ (GCC) 3.4.5)上,代码在没有 delete 语句的情况下迭代几次后出现段错误,并且在我添加 delete 语句时运行正常。

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

附加信息: 当程序到达删除请求时,我的笔记本电脑出现错误:

*** “程序”中的错误:free():下一个尺寸无效(快速):...

其他一些代码:

// 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 进行了简单测试并且循环工作正常,所以我最终从空白开始重建项目并一次添加一个类,以查看问题何时出现。事实证明,我在程序的其他地方向动态分配的数组中添加了额外的内容,而没有更新我用来初始化数组的大小常量。

显然,如果我确保正确删除指针,学校服务器只能处理由此产生的内存差异而不会崩溃(程序运行时间不够长,无法在我的测试中导致严重的内存泄漏),而我的笔记本电脑则不会在我尝试调用 delete(然后会崩溃)之前,我不会注意到内存差异。

最佳答案

假设 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());

the code ran fine without the delete statement and crashed when I added the delete statement.

确定 getNewTT* 的所有权交给您吗?如果您删除它,然后它稍后尝试删除它,您将以堆损坏而告终。如果它将所有权移交给调用者,而您没有删除它,则会发生内存泄漏。

随着您编辑中的附加信息:

char * strVar = new char[11];

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

关于c++ - 在 C++ 中的循环中正确删除动态分配的对象的位置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19694308/

相关文章:

c++ - 我对骑士之旅的实现是无效的,可能是错误的递归调用

c++ - 英特尔芯片组编程

c - 将本地指针传递给函数 FatFs

c++ - 捕获堆栈对象的删除?

perl - 我应该使用哪个工具来找出 Perl 中的内存分配?

c++ - 如何在 Qt 中为 qmake 指定一个库文件依赖?

c++ - Eigen-3.3.5 上的 DiagonalPreconditioner 包装器,用于无矩阵稀疏求解器 CG

C++在不同的函数中重新分配指向动态内存中数组的指针

C指针字符数组到字符数组

c++ - 智能指针和派生类