c++ - 在 C++ 中设计多维数组

标签 c++ memory-leaks memory-management class-design

我想为多维数组设计一个 C++ 类。我所说的多维是指 1d、2d、3d 等。该类支持逐元素加法和标量乘法运算符。假设 A 和 B 是该类的实例(具有相同的大小和维度)。我想在这样的表达式中使用对象:

C = A * 2 + B

我想知道的是如何管理内存。在上面的表达式中,A * 2 会创建一个类的临时对象,这个对象稍后会添加到 B 中。反正添加完成后临时对象就是垃圾。我写了下面的类,它运行良好,但我很确定它会泄漏内存。现在我的问题是,

  1. 如何解决内存问题?设计类(class)的最佳方式是什么?
  2. 是否可以在堆栈而不是堆上分配所需的内存?

    class XArray
    {
        int num_dim;
        int *dims;
        int *index_helper;
        int table_size;
        double *table;
    
    
    public:
        XArray(const int n, const int *d):num_dim(n), dims(d)
        {
            int size = 1;
            for (int i = 0; i < n; i++) {
                size *= d[i];
            }
            table_size = size;
            table = new double[size];
            index_helper = new int[n];
        };
    
        ~XArray()
        {
            delete[] table;
            delete[] index_helper;
        };
    
        int dim(int d)
        {
            return dims[d];
        }
    
        double& operator()(int i)
        {
            index_helper[0] = i;
            return get_helper(1, index_helper);
        }
    
        double& operator()(int i, int j)
        {
            index_helper[0] = i;
            index_helper[1] = j;
            return get_helper(2, index_helper);
        }
    
        double& operator()(int i, int j, int k)
        {
            index_helper[0] = i;
            index_helper[1] = j;
            index_helper[2] = k;
            return get_helper(3, index_helper);
        }
    
        XArray operator*(double m)
        {
            XArray *xa = new XArray(num_dim, dims);
            for (int i = 0; i < table_size; i++) {
                xa->table[i] = this->table[i] * m;
            }
    
            return *xa;
        }
    
        XArray operator+(const XArray &that)
        {
            if (num_dim != that.num_dim) {
                char *msg = new char[100];
                sprintf(msg, "XArray::dimensions do not match in + operation, expected %d, found %d", num_dim, that.num_dim);
                throw msg;
            }
    
            for (int i = 0; i < num_dim; i++) {
                if (this->dims[i] != that.dims[i]) {
                    char *msg = new char[100];
                    sprintf(msg, "XArray::dimension %d not mached, %d != %d", i, dims[i], that.dims[i]);
                    throw msg;
                }
            }       
    
            XArray *xa = new XArray(num_dim, dims);
            for (int i = 0; i < table_size; i++) {
                xa->table[i] = this->table[i] + that.table[i];
            }
    
            return *xa;
        }
    
    private:
        double& get_helper(int n, int *indices)
        {
            if (n != num_dim) {
                char *msg = new char[100];
                sprintf(msg, "XArray::dimensions do not match, expected %d, found %d", num_dim, n);
                throw msg;
            }
    
            int multiplier = 1;
            int index = 0;
    
            for (int i = 0; i < n; i++) {
                if (indices[i] < 0 || indices[i] >= dims[i]) {
                    char *msg = new char[100];
                    sprintf(msg, "XArray::index %d out of range, %d not in (0, %d)", i, indices[i], dims[i]);
                    throw msg;
                }
    
                index += indices[i] * multiplier;
                multiplier *= dims[i];
            }
    
        return table[index];
    }
    

    };

最佳答案

我想念复制构造函数和赋值运算符。您将需要这些来制作内部缓冲区的拷贝,而不仅仅是复制指针,否则您最终将释放相同的内存两次。

如果您要支持 c++0x,您可能还想实现移动语义以获得最佳性能。

像您这样抛出动态分配的对象是一个非常糟糕的主意。

在您的运算符(operator)*中,您应该在堆上创建对象:

XArray operator*(double m)
{
    XArray xa(num_dim, dims);
    for (int i = 0; i < table_size; i++) {
        xa->table[i] = this->table[i] * m;
    }

    return xa;
}

但是,只要您不编写(移动)复制构造函数,这就会崩溃。因为 return 语句将制作一个拷贝,该拷贝引用与 xa 相同的内部数据。 xa 将被销毁,它的析构函数将销毁它的内部数据。因此,返回的临时对象在内部指向已销毁的数据。

编辑:

链接到关于 Move semantics or rvalue references 的信息

关于c++ - 在 C++ 中设计多维数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6606496/

相关文章:

c++ - 如何在二进制文件中存储具有字符串的类对象?

c++ - 内存泄漏/管理建议(方法中的新数组)(c++)

c++ - C/C++如何知道动态分配的数组有多长

c++ - 计算给定类(class)的人数

c++ - 寻找一种更好的方法来初始化 Eigen3 矩阵

python - 在 Debian Wheezy 上使用 flask-sqlalchemy 怪异的内存使用和泄漏

java - 在 Java 中使用 finalize() 是否合适?

c++ - 从 char* 初始化 std::string 而不复制

c++ - 是否可以将 boost 累加器与 vector 一起使用?

ios - 为什么在 performBatchUpdates 中对父 UIViewController 的强引用会泄漏事件?