繁体   English   中英

=运算符是否在C ++中调用构造函数/ new?

[英]Does the = operator call the constructor/new in C++?

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

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

因为我没有内部的默认构造函数operator=功能,在数据this仅仅是垃圾,对不对? 即使我有默认构造函数,它也会被调用吗? 我将上面的代码基于此处的示例。 请注意,为简洁起见,我没有进行输入验证/边界检查。

编辑:我想澄清一下,我只关心这样的电话:

matrix<int> A = B;

其中B已被初始化。

如果您使用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];
    }
}

您现在不再需要担心内存泄漏,也不需要编写析构函数,复制构造函数或赋值运算符。

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

您未实现复制构造函数而违反了规则 (而在C ++ 11中,由于未实现移动构造函数和移动赋值运算符而违反了规则 )。

您的副本分配运算符存在内存泄漏,因为在分配new[] ed数组之前,它不会对旧data数组执行delete[]

尝试以下方法:

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;
    }
    */
};

但是, 复制和交换的习惯用法会更安全:

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) {
        src.swap(*this);
    }
    */

    ~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];
    }

    void swap(matrix<T>& other) noexcept
    {
        std::swap(rows, other.rows);
        std::swap(cols, other.cols);
        std::swap(data, other.data);
    }

    matrix<T>& operator=(const matrix<T>& other) {
        if (&other != this) {
            matrix<T>(other).swap(*this);
        }
        return *this;
    }

    /* for C++11:

    matrix<T>& operator=(matrix<T> &&other) {
        other.swap(*this);
        return *this;
    }
    */
};

在后一种情况下,可以将副本分配和移动分配运算符合并在一起,成为C ++ 11中的单个运算符:

matrix<T>& operator=(matrix<T> other) {
    other.swap(*this);
    return *this;
}

或者,您可以通过使用std::vector遵循零规则,让编译器和STL为您完成所有工作:

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

public:
    matrix(size_t rows, size_t cols) : rows(rows), cols(cols), data(rows*cols) {
    }

    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];
    }
};

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

否,因为只能像其他任何类实例方法一样,在先前构造的对象上调用operator=

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

在您显示的示例中,没有。

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

 matrix<int> A = B; 

该语句根本不调用operator= =的使用只是语法糖,编译器实际上执行了复制构造 ,就好像您编写了此代码一样:

matrix<int> A(B);

这需要尚未实现的复制构造函数,并且编译器生成的复制构造函数不足以对数组进行深层复制。

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

matrix<int> A; // <-- default construction
A = B; // <-- copy assignment

matrix<int> A(B); // <-- copy construction
A = C; // <-- copy assignment

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

没有。

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

没有


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

您可以初始化一个matrix对象,然后对该对象使用operator= 在这种情况下,此matrix对象中的data将不会成为垃圾,因为它已被初始化。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM