【问题标题】:C++ Destructors with Vectors, Pointers,带有向量、指针的 C++ 析构函数,
【发布时间】:2012-08-17 15:07:33
【问题描述】:

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

  • std::vector 和 std::strings:它们会自动销毁吗?

  • 如果我有类似的东西

    std::vector<myClass*> 
    

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

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

    class A {
      ClassB* B;
    }
    

    并且 A 类在代码中的某个位置被销毁。 B 类也会被销毁,还是指针和 B 类仍然存在于内存中的某个地方?

【问题讨论】:

  • "或者只有向量被销毁,但它包含的所有对象仍然存在于内存中?" - 在这里修正你的想法。 vector&lt;myClass*&gt;所包含的对象是myClass*对象,也就是指针类型的对象。它们在向量被销毁时被销毁,但销毁指针不会影响指针指向的对象。所以向量包含的对象不仍然存在于内存中。想象指针指向的对象“包含在向量中”会妨碍您回答自己的问题:-)
  • 顺便说一句,您应该使用每个答案下方的add comment 链接来回复他们或要求澄清。不要使用Post Your Answer 链接!

标签: c++ destructor


【解决方案1】:

std::vector 和 std::strings:它们会自动销毁吗?

是(假设成员变量不是指向std::vector 和std::string 的指针)。

如果我有类似 std::vector 的东西,当调用向量析构函数时会发生什么? 它会自动调用 myClass 的析构函数吗?还是只有向量被销毁,但它包含的所有对象仍然存在于内存中?

如果vector&lt;MyClass&gt; 则向量中包含的所有对象都将被销毁。如果vector&lt;MyClass*&gt; 则所有对象都必须显式为deleted(假设被破坏的类拥有vector 中的对象)。第三种选择是智能指针的vector,如vector&lt;shared_ptr&lt;MyClass&gt;&gt;,在这种情况下,vector 的元素不需要显式为deleted。

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

B 必须明确为 deleted。同样,可以使用智能指针来处理 B 的销毁。

【讨论】:

  • shared_ptr 未提供。我应该下载一些东西吗?提升?
  • @ISTB,是的。有boost::shared_ptr 和boost::scoped_ptr。 C++11 添加了智能指针std::shared_ptr 和std::unique_ptr (#include &lt;memory&gt;)。
  • 顺便问一下,如果我使用shared_ptr,我该如何使用new?我认为 shared_ptr a = new ClassA();不会工作
  • @ISTB,你 shared_ptr&lt;ClassA&gt; a(new ClassA()); 或 shared_ptr&lt;ClassA&gt; a = make_shared&lt;ClassA&gt;();
  • 如果以后我有一个向量<:shared_ptr>> 会发生什么,我在其中使用 shared_ptr a(new ClassA()); 推送 ClassA 对象然后我调用vector.clear(),它会破坏new创建并推入vector的ClassA对象吗?
【解决方案2】:
  • 如果它们在自动存储中,是的。你可以拥有std::string* s = new std::string,在这种情况下你必须自己删除它。

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

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

一个好的经验法则是为代码中的每个new/new[] 使用delete/delete[]。

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

【讨论】:

    【解决方案3】:

    如果我有类似 std::vector 的东西,当调用向量析构函数时会发生什么?

    视情况而定。

    如果你有一个值 std::vector &lt;MyClass&gt; 的向量,那么向量的析构函数会为向量中MyClass 的每个实例调用析构函数。

    如果您有 指针 std::vector &lt;MyClass*&gt; 的向量,那么您有责任删除 MyClass 的实例。

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

    ClassB 实例将保留在内存中。让ClassA 析构函数为您完成工作的可能方法是将B 设为实例成员或智能指针。

    【讨论】:

    • 所以,实际上唯一的问题是当我使用指针时。只要我使用它们,我必须自己摧毁一切。除非我使用智能指针
    • @ISTB。你说得对。请参阅 Luchian Grigore 的答案以获得更好的解释。
    • @ISTB:问题是当你使用原始 owning 指针指向动态分配的对象时,你不应该在向量或其他方式中这样做。拥有指针应该始终是智能指针,但原始指针仍然可以用作非拥有可重新分配的引用。
    【解决方案4】:

    这取决于。 std::vector 和 std::string 和 MyClass 都有一个共同点——如果你声明一个变量是这些类型中的任何一种,那么它将被分配到堆栈上,在你所在的当前块中是本地的,并且当该块结束时被破坏。

    例如

    {
        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
    

    【讨论】:

    • make_unique("Hello World") 怎么会导致std::unique_ptr&lt;std::string&gt; (没有疯狂的表达式模板的东西)?你的意思是make_unique&lt;std::string&gt;("Hello World")(假设一个理智的make_unique函数)?
    • 对不起,我的错只是以某种方式假设存在。尽管stackoverflow.com/questions/7038357/… 有一个理智的实现并不疯狂
    • 那还是需要你指定make_unique构造的类型。
    • 是的,这是我的疏忽。
    【解决方案5】:

    您只需要担心您动态创建的内存(当您使用new 保留内存时。)

    例如:

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

    【讨论】:

    • 如果类成员是指针和公共的,在同一个类中“新建”和“删除”是否更好? (因为看代码更清楚)
    【解决方案6】:

    std::vector、std::string 以及据我所知所有其他 STL 容器都有自动析构函数。这就是为什么最好使用这些容器而不是new 和delete,因为这样可以防止内存泄漏。

    只有当您的向量是 myClass 对象 (std::vector&lt; myClass &gt;) 的向量而不是指向 myClass 对象 (std::vector&lt; myClass* &gt;) 的指针向量时,才会调用您的 myClass 析构函数。

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

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

    【讨论】:

      【解决方案7】:
      1. 是的。 std::vector 和 std::string 在超出范围时会自动完成,同时调用所包含对象的析构函数(对于 std::vector)。

      2. 如前所述,std::vector 在超出范围时被销毁,调用所包含对象的析构函数。但实际上,在这种情况下,包含的对象是指针,而不是指针所指向的对象。所以你必须手动delete他们。

      3. 同(2)。 A 将被销毁,因此指针,但不是 B 指向的类。您必须为 delete B 的 A 提供析构函数。

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-05-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-03-20
        相关资源
        最近更新 更多