【问题标题】:C++: Dynamic memory allocation and class constructorsC++:动态内存分配和类构造函数
【发布时间】:2015-08-03 09:00:03
【问题描述】:

我相信我可能是在滥用 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中的函数min()、max()和mean()仍然很有用,它们继承自data。

我应该如何纠正内存泄漏?

【问题讨论】:

  • 如果你不允许使用std::vector(和模板):-(,你可以实现你自己的my_double_vector,只有内存管理和向量实现。然后用@创建你的data 987654333@ 和额外成员为min、max、mean。
  • 您的代码甚至无法编译,原因之一(除了在class{...} 末尾缺少;)是data 没有默认构造函数,因此您必须在派生的dual_data 成员初始化列表中调用其构造函数,请参阅@Brahim 的答案。
  • @vsoftco 这是一个示例代码,如问题所述,并未提供所有详细信息

标签: c++ oop memory memory-management memory-leaks


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

    由于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 数组,其元素将用于该对中的第二个元素。例如,第零对是(m_data[0], d_data[0])。

    【讨论】:

      【解决方案3】:

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

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

      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) {}
      };
      

      更好的解决方案是不使用继承。总是更好Composititon over inheritance。

      #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 { ... };
      

      【讨论】:

        【解决方案4】:

        首先,实现一个basic矢量类(或者如果可能的话直接使用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;
        };
        

        【讨论】:

          【解决方案5】:

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

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

          【讨论】:

            猜你喜欢
            • 2017-08-17
            • 2015-03-12
            • 1970-01-01
            • 1970-01-01
            • 2014-01-05
            • 2017-06-25
            • 2011-03-11
            • 2020-12-24
            • 2021-07-16
            相关资源
            最近更新 更多