【问题标题】:Details about deleting a variable in c++在 C++ 中删除变量的详细信息
【发布时间】:2015-05-20 18:54:17
【问题描述】:

我试图准确了解 C++ 中删除的变量会发生什么。假设我有类似以下内容。

MyObject * obj;

for (int i = 0; i < 100000000; i++){
    obj = someMethodThatReturnsNewMyObject();
    obj->doSomething();
    delete obj;
}

现在,在实例化时,obj 是一个指向 MyObject 对象的指针。它首先由obj = someMethodThatReturnsNewMyObject(); 行初始化。然后为了好玩而调用了一些方法,并删除了obj。现在我知道当像这样删除某些东西时,它指向的内存空间被删除,并且指针被设置为指向一个空

但是,当 for 循环返回时,我重新初始化指针,导致它分配一个新的内存空间,obj 然后指向这个新空间。但是,指针本身从未从内存中删除。在整个循环中,它只会指向我告诉它指向的任何内容或指向任何内容(删除时)。

那么我的问题是:指针本身,即指针占用的内存空间何时被删除,为什么如果我需要删除内存指向?

【问题讨论】:

  • 自动存储时长。变量在其块的末尾超出范围。在现实生活中,它们会在函数结束时脱离堆栈。
  • 必选:在现代 C++ 中,如果您在应用程序代码中有 delete,那么您做错了。使用shared_ptrunique_ptr(或其他智能指针),并让它们在超出范围时删除对象(如果删除是适当的)。这称为 RAII。
  • 请阅读任何有关指针的任何编程语言书籍。 (或有视频:youtube.com/watch?v=i49_SNt4yfk
  • "并且指针被设置为指向空" 这不会自动发生。这里其实并不需要,但是应该在删除后的循环末尾加上obj = NULL;
  • 你的假设有点不对劲。 delete 函数不会“设置为不指向任何内容”。 delete 调用根本不会触及 obj 的值。它仍然指向相同的内存位置。不同之处在于它指向 /unallocated/ 内存位置,尝试访问它可能会导致意外错误。因此,随后用新值覆盖 obj 是完全可以的。

标签: c++ pointers


【解决方案1】:

指针(变量obj)有automatic storage duration——就像变量i一样。编译器将发出代码为此类变量自动分配内存,并在超出范围时释放它;在调用任何析构函数之后。此内存将在运行时来自堆栈,这使得分配和释放的速度非常快。

顺便说一句,调用delete obj 确实“将指针设置为指向空”。至少如果你的意思是指针被修改。它将继续具有以前的任何值,但该值将不再指向有效的内存位置。

【讨论】:

  • 谢谢,这有帮助。我记错了 delete 实际做了什么,并认为它也将指针设置为空。我想我记得串联命令delete objobj = NULL
  • 是的,虽然我从不喜欢它,但 (delete obj; obj = NULL;) 是旧 C++ 代码中的常见习语。在现代代码中,由于智能指针的普遍使用,您不应该再看到它(当然,智能指针在内部会这样做)。
【解决方案2】:

现在我知道当像这样删除某些东西时,它指向的内存空间被删除,

运行时环境对内存的作用不是由语言指定的。该语言仅指定使用该内存是未定义的行为。

并且指针被设置为指向空。

这是不正确的。指针的值保持原样。它指向不再有效的内存。

指针本身,即指针占用的内存空间,什么时候被删除

它是特定于实现的。在常见的实现中,当函数返回时,运行时环境会回收内存。根据语言,指针的生命周期在其定义范围结束时结束。在其作用域结束后使用指针占用的内存是未定义的行为。

如果你有:

MyObject** ptr = NULL:
for (int i = 0; i < 100000000; i++){

    // obj is defined in the scope of the for loop.
    // It's life ends when the for loop ends.
    MyObject* obj = someMethodThatReturnsNewMyObject();

    obj->doSomething();
    delete obj;

    // Make ptr point to the address of obj.
    ptr = &obj;
}

*ptr = NULL;  // This is undefined behavior since ptr
              // points to memory that is not valid any more.

【讨论】:

    【解决方案3】:

    当程序终止时,指针本身会被删除。您可能不需要删除指针本身,因为您正在重用它,并且它在其存在期间占用相同数量的内存空间。但是,指向的内存会随着循环的每次迭代而被回收,以防止内存被填满。如果你的 for 循环只运行几次,这不会是一个问题,但如果你在没有取消分配空间的情况下循环很多次,它可能可能会填满你的记忆和崩溃你的程序。

    【讨论】:

      【解决方案4】:

      delete 关键字删除指针指向的内存。它不会删除指针本身。

      如何释放指针取决于它的声明位置。如果您的示例代码在方法/函数中,它会在堆栈上声明并在方法/函数返回时释放。如果指针是一个全局变量,那么它将在你的程序中度过。

      【讨论】:

        【解决方案5】:

        它指向的内存空间被清除,指针被设置为指向一个空

        原谅错字,指针没有改变。它仍然指向对象在调用delete 之前的位置。删除后,通过指针使用对象是“不好的”。它可能会工作并访问以前的内容。它可能会访问全部垃圾(例如来自内存重用)。通过指针调用方法很可能会跳转到空间,希望是分段而不是重新格式化您的磁盘。

        您确实希望指针变量保留。每次迭代都会使用它。 delete 可用于释放指针指向的对象中的内存(并运行任何析构函数)。

        【讨论】:

          【解决方案6】:

          当你这样做时:删除 obj

          然后你将obj指向的内存位置标记为删除,并将返回给系统。 Its a bit tricky here larger chucks are mmap'dsmaller ones are managed by heap and deleting it will not be reflected in the system unless it is the topmost。如果它不是堆中的最顶部,则 brk/sbrk 将不会被移动,并且当您下一次询问/分配与标记为删除的大小相同或更小的大小时,它将被重用。该算法有点复杂,但这是要点。

          在您的代码中,在第二次迭代中,obj 可以指向一个完全不同的块/块。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2019-08-23
            • 1970-01-01
            • 2017-02-18
            • 1970-01-01
            • 1970-01-01
            • 2018-03-03
            • 2017-05-17
            • 2021-02-19
            相关资源
            最近更新 更多