使用指针C ++进行内存泄漏

时间:2016-08-31 02:19:49

标签: c++ pointers memory

我是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;
    }
}

头部在标题中定义为

 IntegerNode* head;

6 个答案:

答案 0 :(得分:1)

  

我对是否删除指针本身感到困惑,所以   指针不能再次指向或删除指针所在的位置   指示。

删除指针指向的内容。指针必须指向使用动态范围分配的对象(new关键字)。

  

我只是删除它的所有指针。那会删除像这样的对象吗?   它会在Java?

当然不是。

  

或者我必须手动删除它,我该怎么做?我   记忆漏水???

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

人们常说,如果你已经了解Java,那么从头开始学习C ++比学习C ++更容易。 C ++对象的工作方式与它们在Java中的工作方式完全不同。

并且不仅仅是以不同的方式,而是以完全没有Java相同的方式。例如,在C ++中没有自动作用域中实例化的对象的Java等价物。

在stackoverflow.com上的简短回答中无法完整地解释各种范围的C ++类实例。你需要一本关于C ++的好书,然后开始阅读它。

忘记Java中关于类的所有知识。 C ++类不能那样工作。您继续尝试使用Java进行类比的时间越长,您学习如何正确使用C ++类的时间就越长。

是的,使用智能指针可以帮助解决一些痛苦,这将解决一些痛点。但是理解智能指针本身也需要完全理解C ++的类模型。智能指针并不能解决所有问题,了解C ++类如何工作非常重要,以便了解智能指针解决的问题以及它们无法解决的问题。

答案 1 :(得分:1)

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;
}

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

至于智能指针(引自评论):

  

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

智能指针会在它们自身被解构时删除它们指向的内容(通常是超出范围)。即。

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

答案 2 :(得分:1)

如果您使用new关键字,则始终需要使用delete。使用new分配的内存不受管理。

目前,您的程序正在使用pollFirst方法泄漏内存,因为在重新分配它们之前,您没有释放headtail指向的内存。您可以在重新分配之前致电delete headdelete tail来执行此操作。

如果要自动管理指针所指向的内存,应该考虑使用其中一种智能指针类型,例如unique_ptr

答案 3 :(得分:1)

  

我记忆力泄漏了吗?

是的,如果您new某事,您必须delete某个地方。分配指向nullptr的指针不会影响分配的数据。

  

但是我对是否删除指针本身感到困惑,因此指针不能再次指向,或者它是否删除了指针指向的位置。

delete关键字将删除您发送给它的地址的内容。它不会删除命名变量,因为堆栈中的变量在范围的末尾被破坏。手动删除具有自动存储功能的内容导致undefined behaviour

我发现你对std::unique_ptr感到困惑不,他们并没有删除自己。像任何其他变量一样,它们的析构函数被调用,变量被破坏。关于std::unique_ptr的事情是,在他们的析构函数中,他们删除了他们指向的数据,你必须自己删除它。你应该读一下RAII idom。

关于您的代码,特别是以下几行:

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.

答案 4 :(得分:1)

这取决于头部和尾部的类型。在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 []自由运行。

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

答案 5 :(得分:0)

关于C ++,你应该了解一些事情。

  • 析构函数(DTOR):析构函数是您为类定义的。如果你没有定义自己的编译器的析构函数,那就为你做了。
  • 当您为指针调用delete时,将调用该类的DTOR,从而进行必要的清理。为了测试它,请在DTOR上放置一个断点并运行代码。一旦控制器命中DTOR,检查调用堆栈,你会发现调用堆栈中DTOR下面的最后一帧是你调用delete的行。
  • 就智能指针而言,它与garabage收集器类似。智能指针具有称为引用计数的东西。智能指针的时刻引用计数变为0,调用DTOR。

注意:如果您的类中有数据成员是指针,建议您编写自己的DTOR。