什么是“删除”'新'数据/对象的安全方法?

时间:2013-04-11 13:24:31

标签: c++

例如,如果我创建一个类对象的“新”实例然后“删除”该实例,那么该实例使用的所有内存是否清除(如在释放中)?如果实例创建了其他对象的“新”实例,该怎么办?他们也会受到影响吗?

'删除'究竟是如何工作的?有关如何删除的安全规则/提示吗?如果我真的想要保留某些内容并删除该实例中的所有其他内容该怎么办?

编辑:关于'智能指针',如果我需要在特定时刻删除它,我仍然可以这样做吗?如果是这样,那么它和“新”之间的区别是什么? (除非智能指针在应用程序意外关闭时删除?)

7 个答案:

答案 0 :(得分:1)

使用smart_pointers代替原始指针。

  

'删除'究竟是如何工作的?

调用对象的析构函数,然后调用::operator delete函数,释放内存。

首先提出问题:

由于关键字delete调用了对象的析构函数 - 你应该在析构函数中手动释放内存(如果你使用一些需要释放的资源)。 简单的例子

class A {};

class B
{
public:
    A() : a(new A()) {}
   ~A() { delete a; /* free a's memory */ }
private:
    A* a;
};

答案 1 :(得分:1)

规则1.除非您有充分理由,否则不要使用new

规则2.如果您使用new,则必须在某处对delete进行相应的调用。

关于delete做什么:它调用对象的析构函数(如果有的话),然后释放内存。如果通过"清除"你的意思是"设置用于零或其他值的内存",然后通常不。但是,如果你的意思是"让它可用于其他事情",那么是的,这正是delete所做的。

答案 2 :(得分:0)

不,delete不以任何方式“清除”内存或对象。它 调用对象析构函数,你应该释放对象分配的资源。

答案 3 :(得分:0)

使用new创建对象时,为所有成员分配内存get,并调用一个构造函数 get(取决于您指定的内容)。您可以使用它来创建引用,例如:

public Foo()
{
    m_bar = new Bar();  // Bar* m_bar;
}

但是这不会影响对象的大小。指针(m_bar总是需要4个字节(在32位架构上)的内存,所以对象大小约为8个字节({{1}至少为4个字节和指向构造函数的指针的4个字节) 1

完全相反的是析构函数,在使用m_bar时调用它。您可以使用它来释放所有引用:

delete

因此调用public ~Foo() { if (m_bar) // If the pointer is not NULL, thus pointing anywhere. delete m_bar; // Calls destructor of "Bar" and free it's memory. } ,调用析构函数并释放对象占用的内存,但不会自动引用内存中引用的对象(如此处的delete)。您必须注意,这些对象在析构函数中被删除。如果您忘记为m_bar调用delete,它可能会以我们称之为内存泄漏结束。

使用m_barnew对于您需要尽可能多的性能(例如实时方案)的方案有效,但通常您应该更喜欢使用smart pointers

1 请注意,您无法真正说明对象的实际大小。这取决于编译器如何翻译它。

答案 4 :(得分:0)

  

是否有关于如何删除的安全规则/提示?

是的,着名的RAII(资源分配是初始化)是解决方案。它声明,分配的类的所有内存都应该在构造函数中释放。 C ++保证即使抛出异常,也会调用析构函数,析构函数是解除分配的安全避风港。

  

如果实例创建了其他对象的“新”实例,该怎么办?

您也应该跟踪它们,您可以将它们保留为类的成员并在析构函数中删除它们,否则您可能需要复杂的过程来跟踪它们。

答案 5 :(得分:0)

常规删除实际上有两件事:

  1. 调用指针指向的对象的析构函数。
  2. 释放作为对象本身的内存,即sizeof(object)
  3. 在这两个步骤之间,将调用任何类成员的析构函数(以及任何基类析构函数)。

    请注意,此步骤(即要删除的类成员)仅适用于成员对象。如果成员是指针,它将不会自动调用它们“删除”。因此,你的班级的析构函数需要处理这个问题。

    智能指针实现了这一点。 unique_ptr将始终删除它自己销毁的指针。 shared_ptr将减少指针的引用计数(在许多共享指针之间共享),并且只有在引用计数降为0时才会删除指针。

    因此,通常最好使用对象而不是指针,因为您不需要调用delete。

    在函数范围内,这一点尤为重要,因为在您到达清理阶段之前,可能会抛出异常会导致您退出函数。但是对于自动对象,即使以这种方式退出其范围也将调用其析构函数。 (这就是为什么你必须强制执行析构函数不能抛出的策略,以防这种情况发生)。

    在类的范围内,它不那么重要,因为您可以将逻辑放入析构函数中。但是,如果您的类被复制或分配,那么您必须更加关注何时发生,以及如果构造函数抛出会发生什么(由此不会调用析构函数)。

答案 6 :(得分:0)

可悲的是,除非借助智能指针技巧等,否则没有这种安全的方法可以实现这一点。您可以自由使用“新”和“删除”,因此您负责内存管理。