c++指针内存泄漏

Memory Leak with Pointers C++

本文关键字:泄漏 内存 指针 c++      更新时间:2023-10-16

我是c++新手,我发现我已经被Java和较新的编程语言(如Swift)宠坏了。所以我理解有时候你必须在c++中手动删除对象,比如指针。可以使用delete关键字,也可以使用智能指针。但我很困惑,它是否删除了指针本身,所以指针不能再指向,或者它是否删除了指针指向的地方。

我正在编写的代码,作为一个整数链表。所以我有一个指针指向列表的头和尾。当有人"投票"某事时,它应该从列表中删除它,然后相应地重置头部(或尾部)。所以我有一些代码可以很好地完成我需要它做的事情:

int IntegerLinkedList::pollFirst(){
    if (tail == nullptr && head == nullptr) {
        return 0;
    } else if (head == tail) {
        int ret = head->getData();
        head = nullptr;
        tail = nullptr;
        //delete head;
        //delete tail;
        return ret;
    } else {
        IntegerNode* newHead = head->getNext();
        head->setNext(nullptr);
        newHead->setPrevious(nullptr);
        int ret = head->getData();
        //delete head;
        head = newHead;
        return ret;
    }
}

但是我从来没有真正删除它所指向的对象,我只是删除了所有指向它的指针。这会像在Java中那样删除对象吗?或者我必须手动删除它,我该怎么做?我的记忆泄露了吗??非常感谢

更新头部的代码也是

 void IntegerLinkedList::addFirst(int x){
    IntegerNode* n = new IntegerNode(x);
    if (head == nullptr && tail == nullptr) {
        head = n;
        tail = n;
    } else {
        head->setPrevious(n);
        n->setNext(head);
        head = n;
    }
}

头部在header中定义为

 IntegerNode* head;

Java有一个垃圾收集器,基本上做智能指针做什么。也就是说,当对象的最后一个引用超出作用域时,清理内存。

delete关键字释放指针指向的位置的内存。它实际上不对指针变量本身做任何事情(它只是一个地址)。

纠正你的代码的方法是:

else if (head == tail) { // suppose head = 0xAD4C0080
    int ret = head->getData();
    delete tail; // cleans memory at 0xAD4C0080, head and tail are still 0xAD4C0080
    head = nullptr; // now head = 0
    tail = nullptr; // now tail = 0
    return ret;
} else {
    IntegerNode* newHead = head->getNext();
    head->setNext(nullptr);
    newHead->setPrevious(nullptr);
    int ret = head->getData(); // obtain data while head still exists
    delete head; // get rid of head
    head = newHead; // remove stray reference to deleted memory
    return ret;
}

如果在这些示例中调用delete后尝试使用值0xAD4C0080,则会出现分段错误。

至于智能指针(引用你的评论):

是智能指针,但是它们会删除它所指向的内容还是只删除它们自己

智能指针在自身被解构时(通常是在超出作用域的情况下)删除它们所指向的对象。例如

void func() {
   std::unique_ptr<int> pInt(new int);
} // pInt falls out of scope, std::unique_ptr<int>::~std::unique_ptr<int>() called

我很困惑是否删除指针本身,所以指针不能再次指向,或者如果它删除指针所在的位置指向.

删除指针所指向的对象。该指针必须指向一个被分配了动态作用域(new关键字)的对象。

我只是删除了所有指向它的指针。那样会删除对象吗在Java中呢?

当然不是。

或者我必须手动删除它,我该怎么做?我内存泄漏?

你必须手动删除它,使用delete关键字,是的,你正在泄漏内存,除非你这样做。

人们常说,从头开始学习c++比如果你已经知道Java,尝试学习c++要容易得多。c++对象的工作原理与Java中的根本不同。

不仅不同,而且在Java中根本没有对应的方式。例如,在Java中没有与c++中自动作用域实例化的对象等量物。

c++类实例的各种作用域的完整解释不能在stackoverflow.com上给出一个简短的回答。你需要找一本关于c++的好书,然后开始读。

忘记你所知道的关于Java类的一切。c++类不是这样工作的。你用Java做类比的时间越长,你学习如何正确使用c++类的时间就越长。

是的,使用智能指针可以帮助解决一些问题,它可以解决一些痛点。但是理解智能指针本身也需要完全理解c++的类模型。智能指针并不能解决所有问题,为了理解智能指针解决了什么问题,不能解决什么问题,理解c++类是如何工作的是很重要的。

这取决于头和尾的类型。在c++中,有操作符(例如operator=),也有析构函数。这可能会导致一些有趣的结果。举个例子:

#include <memory>
int main() {
    // allocate memory
    int* ptr = new int;
    // store in smart pointer
    std::unique_ptr<int> smart_ptr(ptr);
    // create another wrapped pointer
    std::unique_ptr<int> smart_ptr2(new int);
    // throw away location of allocated memory
    ptr = nullptr;
    // free memory by assigning to smart pointer
    smart_ptr = nullptr;
    // we can call delete safely here because ptr is null
    delete ptr;
    // data pointed to by smart_ptr2 will
    // be deleted at end of scope
    return 0;
}

此外,还有两个用于分配内存的操作符,operator new和operator new[],必须分别使用delete和delete[]释放它们。

对这些概念的更详细的解释可能超出了本网站的范围。

我内存泄漏吗??

是的,如果你new某事,你必须在某处delete。将指针赋值给nullptr不会影响已分配的数据。

但是我很困惑是否删除指针本身,所以指针不能再次指向,或者如果它删除指针所指向的位置。

delete关键字将删除您发送给它的地址的内容。它不会删除命名变量,因为堆栈上的变量在作用域结束时被销毁。手动删除带有自动存储的内容导致undefined behaviour

我看到你对std::unique_ptr感到困惑,不,他们没有删除自己。像任何其他变量一样,调用它们的析构函数并对变量进行析构。关于std::unique_ptr的事情是,在它们的析构函数中,它们删除了它们指向的数据,而你必须自己删除它。您应该阅读有关RAII的知识。

你的代码有个问题,尤其是这几行:

head = nullptr;
tail = nullptr;
delete head;
delete tail;

这不会做任何事情。您没有删除任何数据,因为headtail不指向任何数据。由于delete关键字删除了数据指针所指向的数据,因此它不会删除任何内容。

但是,以std::unique_ptr:

为例
{
    std::unique_ptr<int> myPtr;
    myPtr = std::make_unique<int>(); // or you can use `new int;`
    myPtr = nullptr; // The old int you allocated with `std::make_unique` is deleted.
    myPtr = std::make_unique<int>(); // assign a newly allocated int
}
// Here, myPtr will free his data as it leaves the scope.

如果您使用new关键字,那么您总是需要使用delete。使用new分配的内存不受管理。

当前您的程序在pollFirst方法中泄漏内存,因为您在重新分配headtail之前没有释放它们指向的内存。您可以通过在重新分配前调用delete headdelete tail来实现这一点。

如果你想要自动管理指针指向的内存,你应该考虑使用一种智能指针类型,比如unique_ptr

关于c++有几件事你应该知道。

    析构函数(DTOR):析构函数是你为你的类定义的东西。如果你不定义析构函数,编译器会为你定义。
  • 当你对一个指针调用delete时,这个类的DTOR被调用,它做必要的清理。为了测试它,请在DTOR中设置一个断点并运行代码。一旦控件命中DTOR,检查调用堆栈,您将发现调用堆栈中DTOR下面的最后一帧是您调用delete的行。
  • 就智能指针而言,它的作用类似于垃圾收集器。智能指针有一个叫做引用计数的东西。当智能指针的引用计数变为0时,调用DTOR

注意:如果在类中有一个指针数据成员,建议编写自己的DTOR