动态内存分配和类构造函数

C++: Dynamic memory allocation and class constructors

本文关键字:构造函数 分配 内存 动态      更新时间:2023-10-16

我相信我可能是误用了OOP,或者是在类构造函数中内存分配出错了。

我将用一个简单的例子来说明我正在做的事情:

class data
{
    data(int n) : m_data(new double[n])
    {
    }
    virtual ~data()
    {
        delete [] m_data;
    }
    double min() { ... }
    double max();
    double mean(); // return minimum, maximum and mean values
    double *m_data;
}
class dual_data : public data
{
    dual_data(int n) : m_data(new double[2*n])
    {
    }
}

我相信这会导致灾难性的内存泄漏。(原因应该很清楚,因为一个构造函数在另一个构造函数之前分配内存,然后用另一个对new的调用覆盖指针。)

如果还不清楚,我有2个类:一个是类似于std::vector的类,它为我处理内存中的数据存储,另一个是派生类,它做同样的事情,但期望数据以x,y对的格式而不是单个值。这样做的原因是,x,y对可以用不同的方式来处理,而不仅仅是一个向量。例如,通过统计数据处理来计算相关性或其他完全不同的东西。但是可以调用dual_data类中继承自datamin()max()mean()函数,这是很有用的。

我应该做什么来纠正内存泄漏?

也许应该这样做:你告诉基类分配一个2*n个元素的数组。此外,基类负责释放内存。不需要析构函数

class dual_data : public data
{
    dual_data(int n) : data(2*n)
    {
    }
}

由于data已经有一个双精度数组,而不是试图与之混淆,只需在dual_data中创建另一个并行的双精度数组。

class data
{
  public:
    data(int n) : m_data(new double[n])
    {
    }
    virtual ~data()
    {
        delete [] m_data;
    }
    double *m_data;
}
class dual_data : public data
{
  public:
    dual_data(int n) : data(n), d_data(n)
    {
    }
    virtual ~dual_data() {
        delete[] d_data;
    }
    double* d_data;
}

现在,您的dual_data类具有原始的m_data数组,以及相同长度的额外d_data数组,其元素将用于对中的第二个元素。例如,第0对将是(m_data[0], d_data[0])

不能初始化父类的变量。不能编译

如果在构造函数中这样做,可能会导致内存泄漏。

class dual_data : public data
{
public:
    dual_data(int n) : data(n)
    {
         m_data = new double[2*n];
    }
};

然而,做好它是你的责任。伟大的粉末是伟大的责任。

你让它这样做:

class dual_data : public data
{
public:
     dual_data(int n) : data(2*n) {}
};

一个更好的解决方案是不使用继承。组合总是比继承好。

#include "data.h"
class dual_data {
public:
     dual_data( int n ) : data_1(n), data_2(n) {}
private:
     data data_1;
     data data_2;
};

更好地使用接口:

class CdataIf
{
public:
     virtual ~CDataIf() = 0;
     virtual double min() = 0;
     virtual double max() = 0;
     virtual double mean() = 0;
};
class data      : public CdataIf { ... };
class data_dual : public CdataIf { ... };

首先,实现一个基本的向量类(或者如果可能的话直接使用std::vector<double>)

class vector_of_double
{
public:
    explicit vector_of_double(std::size_t mSize) :
        mValues(new double[size]{}),
        mSize(size)
    {}
    ~vector_of_double() { delete[] mValues; }
    // implement these if required
    // deleted for now to Respect rule of 3(5) as default implementation is incorrect.
    vector_of_double(const vector_of_double&) = delete;
    vector_of_double& operator = (const vector_of_double&) = delete;
    vector_of_double(const vector_of_double&&) = delete;
    vector_of_double& operator = (const vector_of_double&&) = delete;
    std::size_t size() const { return mSize; }
    // Implement required missing stuff if required as push_back, resize, empty, clear
    // introduction of mCapacity may be required.
    double operator[] (std::size_t index) const { return mValues[index]; }
    double& operator[] (std::size_t index) { return mValues[index]; }
    // To be able to use for range and iterator style
    const double* begin() const { return mValues; }
    const double* end() const { return mValues + mSize; }
    double* begin() { return mValues; }
    double* end() { return mValues + mSize; }
private:
    double* values;
    std::size_t size;
};

那么你可以实现你的类(不用担心内存管理):

class data
{
public:
    explicit data(int n) : m_data(n) {}
    // Or use your own implementation
    // TODO: Handle case with empty vector
    double min() const { return *std::min_element(m_data.begin(), m_data.end()); }
    double max() const { return *std::max_element(m_data.begin(), m_data.end()); }
    double mean() const {return std::accumulate(m_data.begin(), m_data.end(), 0.) / m_data.size();}
private:
    vector_of_double m_data;
};

class dual_data
{
public:
    explicit dual_data(int n) : m_data1(n), m_data2(n) {}
    // your functions as
    std::pair<double, double> means() double {return {m_data1.means(), m_data2.means()};}
private:
    data m_data1;
    data m_data2;
};

我将以不同的方式处理这个问题,而是声明一个包含最小,最大和平均值的接口。然后创建实现接口但具有不同底层结构的类。

struct ICommon
{
  virtual double min() = 0;
  virtual double max() = 0;
  virtual double mean() = 0;
};
class Data : public ICommon
{...};
class DualData : public ICommon
{...};