C++中的析构函数与向量、指针相关问题

54

据我所知,在析构函数中应该销毁使用new创建的所有内容,并关闭已打开的文件流和其他流。但是,我对C++中的其他对象存在一些疑虑:

  • std::vectorstd::string:它们会自动销毁吗?

  • 如果我有以下内容:

    std::vector<myClass*> 
    
  • 指向类的指针。当调用vector析构函数时会发生什么?
    它会自动调用myClass的析构函数吗?还是只有vector被销毁,其中包含的所有对象仍然存在于内存中?

  • 如果我在一个类中有指向另一个类的指针,会发生什么,比如:

    class A {
      ClassB* B;
    }
    

    如果在代码中某个时刻销毁了 Class A,那么 Class B 也会被销毁吗?还是只有指针被销毁了,而 Class B 仍然存在于内存中?


2
“或者只有向量被销毁,但是它所包含的所有对象仍然存在于内存中?” - 在这里修正你的思维。vector<myClass*> 包含的对象是 myClass* 对象,也就是指针类型的对象。当向量被销毁时,它们也会被销毁,但是销毁指针并不会影响指针所指向的对象。因此,向量包含的对象在内存中并不存在。想象指针所指向的对象是“包含在向量中”的,这种想法会妨碍你自己回答问题的能力 :-) - Steve Jessop
1
顺便提一下,您应该使用每个答案下面的“添加评论”链接来回复或请求澄清。不要使用“发布您的答案”链接! - Rook
7个回答

57
和: 它们会自动销毁吗?
是的(假设成员变量不是指向和的指针)。
如果我有类似这样的东西, 当调用vector析构函数时会发生什么?它会自动调用myClass的析构函数吗?或者只有vector被销毁,所有它包含的对象仍然存在于内存中?
如果使用vector,则vector中包含的所有对象都将被销毁。如果使用vector,则必须显式delete所有对象(假设正在销毁的类拥有vector中的对象)。第三种替代方案是智能指针的vector,例如vector>,在这种情况下,vector的元素无需显式delete。
如果在一个类中有另一个类的指针会发生什么?
B必须显式删除。同样,可以使用智能指针来处理B的销毁。

shared_ptr没有提供。我需要下载什么东西吗?Boost? - ISTB
@ISTB,是的。有boost::shared_ptrboost::scoped_ptr。C++11添加了智能指针std::shared_ptrstd::unique_ptr#include <memory>)。 - hmjd
1
顺便问一下,如果我正在使用shared_ptr,那么如何使用new关键字呢?我认为shared_ptr<ClassA> a = new ClassA(); 这样写是不行的。 - ISTB
@ISTB,你使用了 shared_ptr<ClassA> a(new ClassA()); 或者 shared_ptr<ClassA> a = make_shared<ClassA>(); - hmjd
如果我后来有一个vector<std::shared_ptr<ClassA>>,我使用shared_ptr<ClassA> a(new ClassA())将ClassA对象推入其中,然后调用vector.clear(),它会销毁通过new创建并推入向量中的ClassA对象吗? - ISTB

8

您只需要关注动态创建的内存(当您使用new时预留内存)。

例如:

Class Myclass{
   private:
       char* ptr;
   public:
       ~Myclass() {delete[] ptr;};
}

如果类成员是指针并且是公共的,那么在同一个类中使用“new”和“delete”是否更好?(因为这样代码更易读) - Thomas

3
这要看情况。如果您声明一个变量属于std::vectorstd::stringMyClass类型中的任何一种,那么它将被分配在堆栈上,仅在当前块中有效,并在该块结束时被销毁。
例如:
{
    std::vector<std::string> a;
    std::string b;
    MyClass c;
} //at this point, first c will be destroyed, then b, then all strings in a, then a.

如果你使用指针,你猜得没错:只有指针本身占用的内存(通常是4个字节的整数)会在离开作用域时自动释放。除非你明确地使用delete(无论它是否在向量中),否则指向的内存不会发生任何事情。如果你有一个包含指向其他对象的指针的类,你可能需要在析构函数中删除它们(取决于该类是否拥有这些对象)。请注意,在C++11中,有指针类(称为智能指针),让你以类似于“普通”对象的方式处理指针:

例子:

{
    std::unique_ptr<std::string> a = make_unique<std::string>("Hello World");
    function_that_wants_string_ptr(a.get());
} //here a will call delete on it's internal string ptr and then be destroyed

2
make_unique("Hello World") 怎么可能会产生一个 std::unique_ptr<std::string>(不使用疯狂的表达式模板)?你是不是想说 make_unique<std::string>("Hello World") (假设有一个正常的 make_unique 函数)? - Mankarse
抱歉,我的错,我有些假设它会存在。不过有一个理智的实现方式,不会很疯狂,可以参考这里:https://dev59.com/22w05IYBdhLWcg3wxkmr - Cubic
这仍然需要您指定要由make_unique构造的类型。 - Mankarse
是的,那是我的疏忽。 - Cubic

3
  • 如果它们在自动存储中,那么是的。你可以有std::string* s = new std::string,这种情况下你必须自己删除它。

  • 没有什么,你需要手动删除你拥有的内存(对于使用new分配的内存)。

  • 如果你用new分配了b,你应该在析构函数中显式地销毁它。

一个很好的经验法则是,在代码中使用delete/delete[]和每个new/new[]相对应。

更好的经验法则是使用RAII,使用智能指针而不是裸指针。


2
如果我有像std :: vector这样的东西,当调用vector析构函数时会发生什么?
这要看情况。
如果您有一个值的向量std :: vector ,则向量的析构函数调用向量中每个实例的MyClass 析构函数。
如果您有指针的向量std :: vector ,则您负责删除MyClass的实例。
如果我在一个类内部有指向另一个类的指针会发生什么?
ClassB实例将保留在内存中。使ClassA析构函数为您完成工作的可能方法是使B成为实例成员或智能指针。

所以,实际上唯一的问题是当我使用指针时。只要我使用它们,我就必须自己销毁所有东西。除非我使用智能指针。 - ISTB
@ISTB。你是对的。请看Luchian Grigore的答案,那里有更好的解释。 - Andriy
2
@ISTB:问题在于当您在向量或其他情况下使用原始的拥有指针来动态分配对象时,这是您永远不应该做的。拥有指针应始终是智能指针,但原始指针仍可用作非拥有可重新分配的引用。 - Benjamin Lindley

1

std::vectorstd::string以及据我所知的所有其他STL容器都有自动析构函数。这就是为什么通常最好使用这些容器而不是newdelete,因为您将防止内存泄漏。

只有在您的向量是myClass对象的向量(std::vector< myClass >)而不是指向myClass对象的指针的向量(std::vector< myClass* >)时,才会调用您的myClass析构函数。

在第一种情况下,std::vector的析构函数也将为其每个元素调用myClass的析构函数;在第二种情况下,std::vector的析构函数将调用myClass*的析构函数,这意味着它将释放用于存储每个指针的空间,但不会释放用于存储myClass对象本身的空间。

您指向的Class B对象将不会被销毁,但分配给其指针的空间将被释放。


1
  1. 是的。当 std::vectorstd::string 结束作用域时,它们会自动调用所包含对象的析构函数(对于 std::vector 来说)。

  2. 如前所述,当 std::vector 结束作用域时,它会调用所包含对象的析构函数。但实际上,在这种情况下,所包含的对象是指针,而不是指针所指向的对象。因此,您需要手动 delete 它们。

  3. 与第二点相同。A 将被销毁,因此指针也将被销毁,但指向的类 B 不会被销毁。您需要为 A 提供一个析构函数来 delete B。

C++11 中有一个非常有用的解决方案:使用 std::unique_pointer。它只能用于指向单个对象,当指针超出作用域时(例如当您销毁您的 std::vector 时),该对象将被删除。

http://en.cppreference.com/w/cpp/memory/unique_ptr


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接