C++中的操作符是否调用构造函数/新?

C++中的操作符是否调用构造函数/新?,c++,arrays,oop,assign,assignment-operator,C++,Arrays,Oop,Assign,Assignment Operator,假设我有一个不可变矩阵类,它在构造函数中动态创建一个数组,并在解构器中删除它 template <typename T> class matrix { private: T* data; public: size_t const rows, cols; matrix(size_t rows, size_t cols) : rows(rows), cols(cols) { data = new T[rows*cols]; } ~m

假设我有一个不可变矩阵类,它在构造函数中动态创建一个数组,并在解构器中删除它

template <typename T>
class matrix {
private:
    T* data;
public:
    size_t const rows, cols;
    matrix(size_t rows, size_t cols) : rows(rows), cols(cols) {
        data = new T[rows*cols];
    }
    ~matrix() {
        delete [] data;
    }
    //access data
    T& operator()(size_t row, size_t col) {
        return data[row*cols + col];
    }
    matrix<T>& operator=(const matrix<T>& other) {
        //what will this->data contain? do I need to delete anything here?
        //should I call the constructor?
        rows = other.rows;
        cols = other.cols;
        data = new T[rows*cols];
        std::copy(&data[0],&data[0] + (sizeof(T)*rows*cols),&other.data[0]);
        return *this;
    }
}
其中B已经初始化

因为operator=函数中没有默认构造函数,所以这里的数据只是垃圾,对吗

没有

即使我有一个默认构造函数,它会被调用吗

没有

但是,存在内存泄漏。您没有取消分配在构造对象时分配的内存。

如果使用std::vector存储数据,您的类会变得简单得多

template <typename T>
class matrix {
   std::vector<T> data;
public:
    size_t const rows, cols;
    matrix(size_t rows, size_t cols) : rows(rows), cols(cols) {
        data.resize(rows*cols);
    }
    //access data
    T& operator()(size_t row, size_t col) {
        return data[row*cols + col];
    }
}
您现在不必再担心内存泄漏,也不需要编写析构函数、复制构造函数或赋值运算符。

您可以初始化矩阵对象,然后对该对象使用operator=。在这种情况下,该矩阵对象中的数据不会是垃圾,因为它已经初始化

如果将运算符=用于矩阵的未初始化实例,例如矩阵a=b;,其中b已经初始化,这意味着您正在调用由编译器自动生成的复制构造函数。在这两种情况下,都没有垃圾值

假设我有一个不可变矩阵类,它在构造函数中动态创建一个数组,并在解构器中删除它

template <typename T>
class matrix {
private:
    T* data;
public:
    size_t const rows, cols;
    matrix(size_t rows, size_t cols) : rows(rows), cols(cols) {
        data = new T[rows*cols];
    }
    ~matrix() {
        delete [] data;
    }
    //access data
    T& operator()(size_t row, size_t col) {
        return data[row*cols + col];
    }
    matrix<T>& operator=(const matrix<T>& other) {
        //what will this->data contain? do I need to delete anything here?
        //should I call the constructor?
        rows = other.rows;
        cols = other.cols;
        data = new T[rows*cols];
        std::copy(&data[0],&data[0] + (sizeof(T)*rows*cols),&other.data[0]);
        return *this;
    }
}
未实现复制构造函数违反了,未实现移动构造函数和移动赋值运算符违反了C++11中的

您的复制分配运算符存在内存泄漏,因为在分配新的[]ed数组之前,它不会删除[]旧数据数组

请尝试以下方法:

template <typename T>
class matrix {
private:
    T* data;
    size_t const rows, cols;

public:
    matrix(size_t rows, size_t cols) : rows(rows), cols(cols) {
        data = new T[rows*cols];
    }

    matrix(const matrix<T> &src) : rows(src.rows), cols(src.cols) {
        data = new T[rows*cols];
        std::copy(data, &data[rows*cols], src.data);
    }

    /* for C++11:

    matrix(matrix<T> &&src) : rows(0), cols(0), data(nullptr) {
        std::swap(rows, src.rows);
        std::swap(cols, src.cols);
        std::swap(data, src.data);
    }
    */

    ~matrix() {
        delete [] data;
    }

    T& operator()(size_t row, size_t col) {
        return data[(row * cols) + col];
    }

    T operator()(size_t row, size_t col) const {
        return data[(row * cols) + col];
    }

    matrix<T>& operator=(const matrix<T>& other) {
        if (&other != this) {
            delete[] data;
            rows = other.rows;
            cols = other.cols;
            data = new T[rows*cols];
            std::copy(data, &data[rows*cols], other.data);
        }
        return *this;
    }

    /* for C++11:

    matrix<T>& operator=(matrix<T> &&other) {
        delete[] data;
        data = nullptr;
        rows = cols = 0;

        std::swap(rows, other.rows);
        std::swap(cols, other.cols);
        std::swap(data, other.data);

        return *this;
    }
    */
};
matrix<int> A(B);
matrix<int> A; // <-- default construction
A = B; // <-- copy assignment
因为operator=函数中没有默认构造函数,所以这里的数据只是垃圾,对吗

不可以,因为运算符=只能在先前构造的对象上调用,就像任何其他类实例方法一样

即使我有一个默认构造函数,它会被调用吗

在你展示的例子中,没有

我想澄清一下,我只关心这样一个电话:

matrix<int> A = B;
matrix<int> A = B;
它需要一个拷贝构造函数,但您尚未实现,并且编译器生成的拷贝构造函数不足以生成数组的深度拷贝

复制分配看起来更像这样:

template <typename T>
class matrix {
private:
    T* data;
    size_t const rows, cols;

public:
    matrix(size_t rows, size_t cols) : rows(rows), cols(cols) {
        data = new T[rows*cols];
    }

    matrix(const matrix<T> &src) : rows(src.rows), cols(src.cols) {
        data = new T[rows*cols];
        std::copy(data, &data[rows*cols], src.data);
    }

    /* for C++11:

    matrix(matrix<T> &&src) : rows(0), cols(0), data(nullptr) {
        std::swap(rows, src.rows);
        std::swap(cols, src.cols);
        std::swap(data, src.data);
    }
    */

    ~matrix() {
        delete [] data;
    }

    T& operator()(size_t row, size_t col) {
        return data[(row * cols) + col];
    }

    T operator()(size_t row, size_t col) const {
        return data[(row * cols) + col];
    }

    matrix<T>& operator=(const matrix<T>& other) {
        if (&other != this) {
            delete[] data;
            rows = other.rows;
            cols = other.cols;
            data = new T[rows*cols];
            std::copy(data, &data[rows*cols], other.data);
        }
        return *this;
    }

    /* for C++11:

    matrix<T>& operator=(matrix<T> &&other) {
        delete[] data;
        data = nullptr;
        rows = cols = 0;

        std::swap(rows, other.rows);
        std::swap(cols, other.cols);
        std::swap(data, other.data);

        return *this;
    }
    */
};
matrix<int> A(B);
matrix<int> A; // <-- default construction
A = B; // <-- copy assignment

您应该更加关注内存泄漏。您最近的编辑显示了对复制构造函数的调用,而不是对赋值运算符的调用。所以我之前的评论是——你需要编写一个复制构造函数。最初的问题是在错误的观念下提出的,认为赋值操作符是相关的。考虑到最新的编辑,它一点也不涉及。关闭时不清楚。此外,如果您编写了一个副本构造函数,并且它是正确的,那么您链接到的在赋值运算符中使用std::swap的示例或多或少是您编写赋值运算符的方式,即使用简单调用来交换所有成员。矩阵a=B;不是任务,而是初始化。因此,它根本不使用或调用operator=-它调用复制构造函数。相反,或调整大小,只是初始化列表中的datarows*cols。因此,在零示例行规则中,cols和数据由默认的复制构造函数处理?@McAngus:yes,编译器生成的复制构造函数和复制赋值运算符既适用于行和列成员,也适用于数据成员(如果它是符合三/五/零规则的类型,如std::vector)。