如何正确删除 C++ 中的指针? [复制]

Posted

技术标签:

【中文标题】如何正确删除 C++ 中的指针? [复制]【英文标题】:How to delete a pointer in C++ properly? [duplicate] 【发布时间】:2020-06-19 04:17:06 【问题描述】:

我是 C++ 新手,我有一个问题。

假设您使用以下代码声明了变量 x

MyClass *x = new MyClass();

使用这个变量后,我不再需要它了。

在以下命题中,那么首选的行动方案是什么?有什么区别?

    致电free(x);

    致电x->~MyClass();

    致电MyClass::~MyClass(p);

    致电delete x;

谁能帮我理解这个?

提前致谢。

【问题讨论】:

new创建的变量应该用delete删除 首选的做法是首先不要写MyClass *x = new MyClass();,而是MyClass x;,或者如果您确实需要动态分配,请使用智能指针 请使用 std::make_unique 作为创建指针的默认方式! 你根本不使用new。而是使用std::unique_ptr<T> var = std::make_unique<T>(); @RamblinRose 这不是重复的,它是关于放置新的 【参考方案1】:

如果您通过new 创建实例:

MyClass *x = new MyClass();

必须通过delete删除它:

delete x;

1.) 致电free(x);

没有。 free 只释放它不调用析构函数的内存。如果你malloc内存你需要free它,但是你很少在C++中使用malloc并且在从new获得的指针上调用free是错误的。

2.) 致电x->~MyClass();

没有。显式调用析构函数几乎总是错误的!

(例如,当您通过placement new 创建对象时,您不会直接调用delete,而是直接调用析构函数,因为placement new 会在已分配的内存中创建对象。)

3.) 致电MyClass::~MyClass(p);

没有。这是没有意义的,析构函数不带参数。

4.) 致电delete x;

是的。 Calling delete...

销毁以前由新表达式分配的对象释放获得的内存区域

但是你不应该手动管理内存。要么依赖自动存储:

MyClass x;

x 的析构函数在超出范围时被自动调用。或者,如果您确实需要动态内存分配,请使用 smart pointers。

进一步阅读:Why should C++ programmers minimize use of 'new'? 顺便说一句,这是一个常见的误解,以至于我记得每一次关于 Stroustrup 的演讲都有一个使用new 创建对象的示例,然后他解释说绝对不应该使用new。实际上,除了忘记打电话给delete之外,还有更多的事情要做。考虑:

  
     MyClass *x = new MyClass();
     foo();   
     delete x;   // phew I didnt forget to call delete
 

如果foo 抛出异常,则此代码会泄漏内存。正确的做法是依靠RAII:

  
     MyClass x;
     foo();   
 

现在如果foo 抛出异常,x 的析构函数将被调用!

【讨论】:

我同意删除部分。除此之外,在我的公司内,始终让这个指针指向 0 是一种惯例,例如delete x; x = 0; @dejoma 巧合的是,我最近回答了一个关于此的问题。将指针设置为nullptr 有一个(有限的)用途,但它的主要效果是一种虚假的安全感。见这里:***.com/a/60522321/4117728。它不能解决手动使用newdelete 带来的一般问题 除此之外,在我的公司内部,总是让这个指针指向 0 是一种惯例——我知道这有什么影响只有一个原因—— 0 指针表示需要分配对象。如果像这样使用它:if (ptr != nullptr) delete ptr; 可以完全删除对 nullptr 的检查,因为删除 nullptr 是完全有效的。如果使用它是因为您的程序流程发生了很多曲折以至于您不知道指针的状态,那么可能需要审查代码。 "如果您通过new 创建实例...您必须通过delete 删除它" - 除非您使用placement-new,否则不要完全使用delete,你必须直接调用类型的析构函数ala #2 @RemyLebeau 谢谢,添加了注释。我认为“如果......你必须”仍然很好,因为它指的是 OP 代码【参考方案2】:

使用new 关键字动态分配的变量应使用delete 关键字删除。 newdelete 调用指定类的构造函数和析构函数。这意味着您的实例已正确初始化和取消初始化。

所以,用MyClass *x = new MyClass(); 初始化的实例x 应该用delete x; 删除。

但是,如果可能的话,最好在堆栈上声明变量,如 MyClass x; 并让 RAII 完成它的工作。看看下面的例子:


    // creates an object 'x' on stack
    MyClass x;

    // do something with 'x'

    // once the object is out of scope, it is automatically being destructed

此外,如果您仍需要动态分配,现代 C++ 建议使用智能指针,例如 std::shared_ptrstd::unique_ptr。智能指针会自动代替您处理内存。换句话说,通过使用智能指针,您无需关心deleteing 使用new 创建的对象。你可以这样写:


    // creates an object 'x' on heap
    // its default ctor is being called
    std::shared_ptr<MyClass> x = std::make_shared<MyClass>();

    // once the object is out of scope, even though it is allocated
    // on the heap, there is no need to call 'delete' here because
    // deletion is automatically handled by the 'std::shared_ptr'

【讨论】:

请注意,RAII 的重点是x 无论如何都会被销毁,即使存在异常(或return),如果范围将始终保留在那么实际使用newdelete 就不会那么重要了。刚刚意识到您的“//一旦对象超出范围”表明您始终将范围留在,因为我最终得到了与您类似的示例。无论如何,你有我的 +1, @idclev463035818 是的,感谢您指出这一点。无论如何,你也有我的 +1。

以上是关于如何正确删除 C++ 中的指针? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

c ++:原始指针映射中的复制,删除和运算符=

用于删除 Map 中的指针值和指针向量的 C++ 通用代码

在 C++ 中删除空指针是不是被认为是未定义的行为? [复制]

删除指针 C++ 时的核心转储

如何从 C++ 中的字符串中删除前缀或后缀? [复制]

C++中的指针和删除