C++析构函数删除共享内存。

4
我有一个用C ++编写的程序,它执行以下操作:获取一个未排序的整数数组并将其按升序划分为子数组。例如,我的数组是1,2,3,-2,4。 因此,输出将是: 1,2,3 //子数组1 -2,4 //子数组2
我需要的方法是分配指针数组,并且该数组中的每个单元格将指向包含一个系列的子数组(也是动态分配的)。此外,我不允许更改“主”函数。
现在,我有一个“打印”方法,该方法使用运算符重载打印子数组。
我检查了并发现打印方法正常工作,但在这段代码中:
cout << "\ns3: \n";
  print(s3);

  s3 = s1;
  cout << "\ns3 again: \n";
  print(s3);

print(s3)可以正常输出,但在赋值操作符之后再次调用print(s3)时,输出内容是垃圾字符。经过一些调试,我认为这与析构函数有关。

如果有人能够指出问题并提供解决方案,我将非常感激。当然我会提供源代码。

更新

我想解释得更清楚一些:每次调用“print”时,在跟踪调用的过程中,第一个执行的事情是复制构造函数。当我在复制构造函数中设置断点时,我看到函数签名中的指针“src”指向正确的位置(数组的第一个元素),但在s3=s1赋值之后,再次调用print(s3)时,复制构造函数中的指针就变成了垃圾数据。

**

以下是代码:

   // HW4.cpp : Defines the entry point for the console application.
//

#include <iostream>
using namespace std;


//global declerations and indexes//
typedef long int * LONG_INT_PTR;        

//class     
class SeriesArray
{
//members declerations
private: 
        LONG_INT_PTR *stable;
        int *count_arr;   //help array that indicate how many serieses made from the array and how many element in each series
        int count_size;   //  help counter
        int size;

public:
        SeriesArray::SeriesArray(LONG_INT_PTR arr, int n );
        SeriesArray::SeriesArray(const SeriesArray& src );
        SeriesArray::~SeriesArray();
        long int SeriesArray::get_entry(int i,int j) const;
        SeriesArray& SeriesArray::operator=(const SeriesArray& src);
        friend ostream& operator<<(ostream& stream, const SeriesArray& src);//global - not member
};


//members implementation
        //default constructor
        SeriesArray::SeriesArray(LONG_INT_PTR arr, int n )
        {
            size=n;
            int j=0;
            int s=0;
            count_size=0;
            count_arr=new int[size];
            for (int i=0;i<size;i++)
            {
                if (arr[i]<arr[i+1])
                    count_size++;
                else
                {
                    count_size++;
                    count_arr[j]=count_size;
                    j++;
                    count_size=0;
                }
            }
            size=j;
            stable=new LONG_INT_PTR[size];
            for (int i=0;i<size;i++)
            {
                stable[i]=new long int[count_arr[i]];
                for (int k=0;k<count_arr[i];k++)
                {
                    stable[i][k]=arr[s];
                    s++;
                }
            }

    }

    //copy constructor
    SeriesArray::SeriesArray(const SeriesArray& src )
    {

            size=src.size;
            count_arr=new int[size];
            stable=new LONG_INT_PTR[size];
            for (int i=0;i<size;i++)
            {
                count_arr[i]=src.count_arr[i];
                stable[i]=new long int[count_arr[i]];
            }
            memcpy(this->stable,src.stable,src.size*sizeof(long int));
    }

    //destructor
    SeriesArray::~SeriesArray()
    {
        for (int i=0;i<size;++i)
                delete[] stable[i];
        delete[] this->count_arr;
        count_size=0;
    }

    //member
    long int SeriesArray::get_entry(int i,int j) const
    {

        if (i<this->count_size&&this->stable[i][j]!=NULL)
            return (this->stable[i][j]);
        else return NULL;
    }


    //overload = operator
    SeriesArray& SeriesArray::operator=(const SeriesArray& src)
    {
        if (this==&src)
          return *this;

        if (stable!=NULL)
            delete[] stable;
        if (count_arr!=NULL)
            delete[] count_arr;
            //for (int i=0;i<size;i++)
            //  delete[] stable[i];
            size=src.size;
            count_arr=new int[src.size];
            memcpy(count_arr,src.count_arr,src.size*sizeof(int));
            stable=new LONG_INT_PTR[size];
            for (int i=0;i<size;i++)
            {
            //  count_arr[i]=rhs.count_arr[i];
                stable[i]=new long int[src.count_arr[i]];
            }
            memcpy(stable,src.stable,src.size*sizeof(long int));

        return *this;
    }


//***************************************************************************************************************************************************//
//global//

    //overload operator <<
    ostream& operator<<(ostream& stream,const SeriesArray& src)
    {
        for (int i=0;i<src.size;i++)
        {
        for (int j=0;j<src.count_arr[i];j++)
         {
            stream << " " << src.stable[i][j] << " " ; 
         }
        stream << "\n\n\n" ;
     }

        return stream;
    }

    //print
    void print(SeriesArray src)
    {
         cout << src;
        cout << "\n";
    }  // print



//main  
int main()
{
  long int arr1[20] = {23, 91, -71, -63, 22,  55, 51, 73, 17, -19,
                      -65, 44, 95,  66, 82, 85, 97, 30, 54, -34};
  long int arr2[10] = {0, 1, -7, -6, 2,  5, 6, 7, 1, -1};

  int count[20], i, j, n =20, sno;

  long int *parr[20];

  SeriesArray s1(arr1, 20);
  SeriesArray s2(arr2, 10);
  SeriesArray s3(arr2, 10);


  cout << "\narr1:\n";

  for(i=0; i < 20; i++)
    cout <<  "  " << arr1[i] << "  ";
  cout << "\n";

  cout << "\n\ntable:\n";
  print(s1); 

  cout << "\narr2\n";

  for(i=0; i < 10; i++)
    cout <<  "  " << arr2[i] << "  ";
  cout << "\n";

  cout << "\n\ntable:\n";
  print(s2);

  cout << "\ns3: \n";
  print(s3);


  s3 = s1;
  cout << "\ns3 again: \n";
  print(s3);

  cout << "\ns1 again: \n";
  print(s1);

  cin>>i;
 return 0;
} // main 

你删除了已分配的空间,然后进行memcpy操作吗? - Leeor
@Leeor 内存在其中被重新分配。虽然不是异常安全的,但实际上并没有错。 - Alan Stokes
首先;-) 1)你的代码不符合g ++。我假设你正在使用Visual Studio(https://dev59.com/KW035IYBdhLWcg3wErzM)?为了编译你的代码,我必须#include <cstring>并删除SeriesArray ::从你的函数声明(仅在那里)。2)检查你的程序输出。你的表总是缺少最后一个数组条目,甚至更糟的是访问不再属于数组的内存(检查构造函数中的第一个循环)。 - el_tenedor
起始输出正确无误,但在赋值运算符之后的输出是垃圾(即在s3=s1之后),我正在使用C++编程而非g++。 - Shay
@user2826463,实际上我是在指 arr[i]<arr[i+1] 这一行。前面的 for 循环将 i 增加到 (size-1)。arr 是一个大小为 (size-1) 的数组。如果你访问 arr[(size-1)+1],那么你就超出了数组的边界。你确定 print(s1); 这一行的输出结果吗?当我数元素时,我得到的是 19 而不是 20。输入的 -34 缺失了。顺便说一下:g++ 是 GCC(GNU 编译器集合)的 C++ 前端,而不是一种编程语言 ;-) - el_tenedor
3个回答

2
问题出在你的赋值运算符上,这个操作几乎是正确的,但“几乎正确”并不够好。
        for (int i=0;i<size;i++)
        {
        //  count_arr[i]=rhs.count_arr[i];
            stable[i]=new long int[src.count_arr[i]];
        }
        memcpy(stable,src.stable,src.size*sizeof(long int));

我想您的意思是:
        for (int i = 0; i < size; i++)
        {
            stable[i] = new long int[src.count_arr[i]];
            memcpy(stable[i], src.stable[i], src.count_arr[i]*sizeof(long int));
        }

你的复制构造函数中有相同的错误

SeriesArray::SeriesArray(const SeriesArray& src )
{

        size=src.size;
        count_arr=new int[size];
        stable=new LONG_INT_PTR[size];
        for (int i=0;i<size;i++)
        {
            count_arr[i]=src.count_arr[i];
            stable[i]=new long int[count_arr[i]];
        }
        memcpy(this->stable,src.stable,src.size*sizeof(long int));
}

应该是

SeriesArray::SeriesArray(const SeriesArray& src )
{

        size=src.size;
        count_arr=new int[size];
        stable=new LONG_INT_PTR[size];
        for (int i=0;i<size;i++)
        {
            count_arr[i]=src.count_arr[i];
            stable[i]=new long int[count_arr[i]];
            memcpy(stable[i], src.stable[i], src.count_arr[i]*sizeof(long int));
        }
}

对于你第一次尝试使用2D数组来说,这并不是一个坏的尝试。


已经按照您的解决方案所建议的做了,但在循环内进行4-5次分配后,程序会崩溃并出现异常。 - Shay
@user2826463,请查看我的编辑答案,当你调用print时会调用复制构造函数,由于它存在错误,因此您随后会遇到崩溃。 - john
谢谢John,你解决了这个问题!! :) 你能解释一下问题出在哪里吗?为什么程序会崩溃,改变前后实际发生了什么? - Shay
1
@user2826463,你只是没有正确地复制稳定的数组。stable是一个指针数组。你正确地为每个指针分配了内存。但是,在分配完之后,你必须将src.stable[i]指向的内容复制到stable[i]指向的位置。你必须为每个stable[i]都这样做。相反,你的代码只是复制了src.stable 指针,而没有复制它们所指向的内容 - john

1
在你的赋值运算符中,你需要复制每个单独条目在stable中的内容,而不是一次性复制整个内容使用memcpy
(更好的方法是改变你的赋值运算符使用复制和交换,或者更好的使用vector并使整个东西缩小十倍。)
顺便说一下,你可能想让print使用一个const引用而不是复制它的参数。

尝试了那个,结果一样:(。我也稍微更新了一下我的问题。 - Shay

0

我尝试了你的程序,发现有一些错误导致程序在运行时失败(使用gcc编译程序)。

void print(SeriesArray src)

这是一个按值调用。它将导致函数print调用复制构造函数(请查看this页面)。一旦离开print,src将被删除(程序将调用析构函数)。这是一个问题,因为您正在使用动态分配的内存。最好通过引用来调用它,这将强制print使用重载的=赋值运算符。

void print(SeriesArray & src)

接下来是一个无效的指针,正如你在我的评论中已经读到的那样。此外,你没有为stable分配足够的空间。你应该像这样重写你的构造函数 - 或者如果你想要更优雅的方式...

SeriesArray::SeriesArray(LONG_INT_PTR arr, int n )
{
    size=n;
    int j=0;
    int s=0;
    count_size=1;
    count_arr=new int[size];
    for (int i=0;i<size-1;i++)
    {
        if (arr[i]<arr[i+1])
            count_size++;
        else
        {
            count_arr[j]=count_size;
            j++;
            count_arr[j]=1;
            count_size=1;
        }
    }
    size=j+1;
    stable=new LONG_INT_PTR[size];
    for (int i=0;i<size;i++)
    {
        stable[i]=new long int[count_arr[i]];
        for (int k=0;k<count_arr[i];k++)
        {
            stable[i][k]=arr[s];
            s++;
        }
    }
}

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