【问题标题】:C++, copy constructor confusionC++,复制构造函数混淆
【发布时间】:2013-03-06 21:52:58
【问题描述】:

假设我创建了一个自定义 Array 类并具有以下构造函数:

    Array::Array(size_t size)
    {
      mySize = size;
      //myData is of type int*
      myData = new int[mySize]; // this stuff is allocated on a heap
    }

据我所知,在这种情况下,默认的复制构造函数会这样实现:

    Array::Array(Array& a)
    {
      mySize = a.mySize;
      myData = a.myData; //points to the same memory on the heap
    }

最后,假设我的 main.cpp 文件中有以下代码

     int main()
     {
       Array a(1);
       Array b(a); //copy constructor is invoked
     }

由于删除指向空闲存储内存的 myData 指针,我预计会发生内存泄漏,但我有以下运行时错误:

*** glibc detected *** ./main.out: double free or corruption (fasttop): 0x086ad008 ***

为什么?似乎 ~Array() 以某种方式自动释放分配在堆上的内存 - 但这对我来说非常违反直觉。也许我错过了什么?

更新:

      class Array{
         private:
           size_t mySize;
           int *myData;
           ...

更新 2:

main.cpp:

   #include <iostream>
   #include "array.h"

   int main()
   {
     Array a(1);
     Array b(a);
   }

数组.h:

   #ifndef ARRAY_H_
   #define ARRAY_H_
   #include <stddef.h>
   class Array{
   private:
       size_t mySize;
       int *myData;
   public:
       Array(size_t size);
       ~Array();
       void set(int i,int val);
       int get(int i);
       size_t getSize();
   };
   #endif

array.cpp:

   #include "array.h"

   Array::Array(size_t size)
   {
     mySize = size;
     myData = new int[mySize];
   }

   Array::~Array()
   {
     delete[] myData;
   }

   void Array::set(int i, int val)
   {
     if(i>=0 && i<mySize)
       myData[i] = val;
   }

   int Array::get(int i)
   {
     if(i>=0 && i<mySize)
       return myData[i];
     else return -1;
   }
   size_t Array::getSize()
   {
     return mySize;
   }

【问题讨论】:

  • 你是说你的析构函数没有释放内存吗?如果是这样,则很难理解错误。
  • What is The Rule of Three? 的可能重复项
  • 我是说析构函数可能会释放指向堆的内存,它不应该......至少据我所知。
  • 析构函数不会做这样的事情,除非你告诉它。可以发sscce吗?
  • 你能发布整个课程吗?您是否定义了赋值运算符?析构函数?自定义delete 实现? Array 有什么子类吗?

标签: c++ gcc c++11 gcc-warning


【解决方案1】:

我认为在你的析构函数中你有

 Array::~Array(void)
 {
      delete [] myData; //points to the same memory on the heap
 }

问题是双重释放

例子:

int main()
{
       Array a(1);  // here a.myData = 0x12345678
       Array b(a); //copy constructor is invoked // here b.myData = 0x12345678

       // pop  stack (call destroy of object)
       // delete b.myData
       // delete a.myData already delete
}

双倍免费

编辑: 对于您的复制构造函数,请使用 const,因为您不修改 a。

 Array::Array(const Array& a)
 {
      mySize = a.mySize;
      myData = a.myData; //points to the same memory on the heap
 }

祝你好运!

【讨论】:

  • 谢谢,我完全忘记了 delete[] 运算符。所以,delete[] 一定是在析构函数中自动调用的。
  • @ВладиславБураков 不,它不会自动调用。
【解决方案2】:

所以...尽管您声称,事实证明您确实删除了析构函数中的数组,而复制构造函数是浅拷贝,因此您得到了双重删除。很简单。

Array::~Array()
{
  delete[] myData;
}

由于这是一个动态数组,它应该拥有数据,因此您可以在析构函数中删除,但您需要在复制构造函数中“深度”复制赋值运算符。见the rule of three

【讨论】:

  • 重新“需要深度复制”——或引用计数,或禁用复制。
  • @Cheersandhth.-Alf 好的,但我想一个简单的动态数组应该具有简单的数据所有权语义。并且是可复制和可分配的。
【解决方案3】:

你的副本是浅拷贝,所以如果你有一个释放内存的析构函数,每个对象都会尝试删除相同的内存。

你没有做一个浅拷贝。您可以编写自己的显式复制构造函数,将实际数据复制到新分配的数组中。

我喜欢 Google 对 disable copy and assignment constructors 的建议,并且更喜欢明确的 CopyFrom() 方法。

【讨论】:

    【解决方案4】:

    "double free" 表示同一个指针已被分配给delete[] 两次。因为在你的析构函数中(大概)它在对象ab 中都是delete[]-ed。实用的解决方案:使用std::vector,不要乱用原始数组等。

    【讨论】:

    • 哦,原来destructor中会自动调用delete[]?
    • @ВладиславБураков:不,它不会自动调用。大概是你,或者写代码的人,把它放在那里。很难说,因为你忘了出示那段代码。
    • 不,我没有展示其余的,因为除了构造函数我没有覆盖其他任何东西
    • @ВладиславБураков:呃,你提供的信息与实际不符。您能否提供一个展示所描述行为的完整小示例。
    • 您已经说过 两次,现在您相信 delete[] 会被自动调用,并且您被告知您错了。您能否发布Array 类的整个 代码,或显示此错误的完整的小示例
    【解决方案5】:

    我认为您的析构函数(来自数组“a”和“b”)正在尝试释放相同的内存(双重释放)。也许你应该在释放之前检查你的 myData。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-04-01
      • 2013-06-25
      • 1970-01-01
      • 2017-09-11
      • 1970-01-01
      • 2014-09-20
      • 1970-01-01
      • 2017-03-18
      相关资源
      最近更新 更多