【问题标题】:Initialize C++ pointers to ZERO after we delete?删除后将 C++ 指针初始化为零?
【发布时间】:2011-07-21 21:07:28
【问题描述】:

在 C++ 中,我们大多数时候使用delete 运算符来删除对象。

delete 不会将指针值设为 NULL。有什么办法可以自动实现吗?

例如

int *p = new int;
delete p;  // this should deallocate object pointed by p
           // and also initialized value of p = NULL

【问题讨论】:

  • 您为什么认为这是个好主意?搜索其他问题和/或谷歌搜索它,你会发现它并不清楚这实际上不会隐藏代码中的错误(双重删除,第二次删除被 忽略 作为指针之前设置为 0)

标签: c++ pointers memory-management


【解决方案1】:

您的建议有两个问题。

一种虚假的安全感

你的提议会引起一种虚假的安全感。当然,标准保证如果您在空指针上调用delete,它不会崩溃。但是,您忘记了一个小事实:没有一个指向您的对象的指针。

int* p = new int(8);
int* q = p;
delete p; p = 0;
delete q; // Undefined Behavior

因此,这种做法是没有用的。因为一种虚假的安全感比没有安全感更糟糕,我实际上强烈反对它。希望大家在申请deletenilly-willy前三思。

这就引出了第二个问题

你不敢用delete

delete 应该保留给智能指针或其他容器的实现者。以下适用:

  • 仅供专家使用
  • (专家)不要*

*对于您想要实现的目标,可能已经存在已调试的实现。

大量现有的工具来管理内存:

  • 无处不在的各种智能指针:std::unique_ptrstd::auto_ptr(取决于您的 C++ 版本)、std::scoped_ptrstd::shared_ptr(及其类似的 std::weak_ptr,或它们的 boost/tr1 等效项)
  • 无处不在的各种风格的容器:boost::arrayboost::scoped_arraystd::vector(以及其他)
  • 以及鲜为人知但在 OO 中非常有用的:boost::ptr_vector(和 co)
  • 甚至还有 boost::intrusive_ptr 和 Boost Intrusive Containers 库或 Boost MultiIndex 库(带有 BiMap 衍生工具)
  • 可能还有其他几个 boost 库,可能更专业,例如 Boost.Signals

面对如此多样化的野生动物,很难想象您突然发现了一种使用数据的新方法,这种方法与我们所做的如此不同,以至于您需要其他东西。如果您有,请随时发布,我们将帮助您了解如何使用这些工具来适应您的情况(或为您提供有关如何创建新形式的智能指针的指示)。

【讨论】:

    【解决方案2】:

    反正也没多大帮助,因为可能有不止一个指向被删除对象的指针。

    int* p = new int;
    
    int* q = p;
    
    delete p;   // how do we NULL q?
    

    最好的办法是在 p 超出范围之前使用 delete。或者使用标准容器,这样我们就不需要 new/delete。

    【讨论】:

      【解决方案3】:

      您可以编写自己的包装函数或宏来执行此操作。 但是,在一般情况下很难,因为您可以将右值传递给删除运算符。那么它应该将 NULL 分配给什么?

      【讨论】:

      • 抱歉,我无法理解您的陈述您可以将右值传递给删除运算符,您能详细说明一下吗?如何将右值传递给delete
      • 实际上,右值问题可以在 C++0x 中使用右值引用来解决...使用右值,您确定不需要无效。
      【解决方案4】:

      没有任何测试,我给你这个:

      template <typename T> void deleteAndNull(const T*& pointer){
          delete pointer;
          pointer = 0;
      }
      

      【讨论】:

      • 实际上我不确定语法,但我打算将它作为对指针的引用。我不确定,但我认为这将防止尝试删除不是指针的东西
      • @Nawaz:在这种情况下没关系:)
      • 两者是等价的,用你的形式,T将被推导出为Foo,而更简单的T&amp;T将被推导为Foo*。只要您不忘记&amp;pointer 的类型就不会改变。有人可能会争辩说,从某种意义上说,您的表单更好,因为它可以帮助减少重载分辨率……但是这个函数非常专业,它是一个边际收益(为什么不接受它!)
      • 其实:T const *&amp;pointer。想想X const *pX = new X(1,2,3); ...; deleteAndNull(pX);
      【解决方案5】:

      可能是使用带有指针的 auto_ptr 也会节省您的时间。

      【讨论】:

        【解决方案6】:

        这样写很简单:

        template<class T>
        void safe_delete(T*& p)
        {
            delete p;
            p = NULL;
        }
        int main()
        {
            int* p = new int;
            safe_delete(p);
        
            double* p1 = new double;
            safe_delete(p1);
        
        }
        

        注意不要在数组中使用它:)

        【讨论】:

          【解决方案7】:

          您可以编写自己的函数来做到这一点:

          void deleteAndReset (void** p)
          {
              delete *p;
              *p = null;
          }
          

          【讨论】:

            【解决方案8】:

            与您的其他指针问题相同的答案 - 使用 smart pointer。重新发明轮子是没有意义的。

            【讨论】:

              【解决方案9】:

              这样做是非常糟糕的做法。

              他们说如果存在双重删除,它将使您的程序免于崩溃。 唉,在你删除它指向的对象后将指针设为 NULL,只是掩盖了问题:你的程序包含错误。

              我向你保证,在这种情况下,你希望你的程序尽可能早地崩溃。

              【讨论】:

                【解决方案10】:

                执行此操作的最简单方法是将操作符 delete 覆盖为

                • 擦除内存
                • 清空指针

                阅读运算符重载是我的建议。 这样,您可以保留所有当前代码,而不必费力将所有内容更改为函数调用。

                【讨论】:

                • 您不能覆盖delete 运算符,只能覆盖operator delete
                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2011-04-10
                • 1970-01-01
                • 2013-06-01
                • 1970-01-01
                • 2017-09-06
                • 2016-12-11
                • 1970-01-01
                相关资源
                最近更新 更多