首页 > 解决方案 > 运算符重载 = 修改原始对象

问题描述

struct List {
    int size;
    int* items;
    List& operator=(const List& l);
};

List& List::operator=(const List& l)
{
    delete[] items;
    size = l.size;
    items = new int[20];

    for (int i = 0; i < size; i++)
        items[i] = l.items[i];

    return *this;
}

ostream& operator<<(ostream& out, const List& l)
{
    out << "Size: " << l.size << "\t {";
    for (int i = 0; i < l.size; i++)
        out << l.items[i] << " ";

    return (out << "}");
}

int main()
{
    int size = 6;
    List l1 = { size, new int[size]{ 0, 1, 2, 3, 4, 5 } };
    List l2 = l1;

    l2.items[1] = 50;

    cout << l1 << endl;
    cout << l2 << endl;

    return 0;
}

我很困惑,因为当我使用重载运算符分配l2 = l1时,为什么 l1 的内容会在稍后更改 l2 时发生变化?特别是因为 l1 作为 const 传递。它们以某种方式指向内存中的同一个对象,而不是副本。

标签: c++operator-overloading

解决方案


List l2 = l1;不调用复制赋值运算符 ( operator=(const List& l))。由于“赋值”发生在变量声明期间,您改为l2通过复制初始化进行初始化,该初始化调用编译器生成的默认复制构造函数。由于它进行了浅拷贝,因此两个对象都将指向相同的数据。

如果您要编写自己的管理内存/资源的类,您至少需要提供自己的复制构造函数、复制赋值运算符和析构函数。这被称为三法则。如果要包含移动语义,则需要提供移动构造函数和移动赋值运算符,这被称为 5 规则。还有零规则,使用已经“做正确的事情”的类型(就像使用 a ) 允许编译器生成的默认值为您工作,您可以在三/五/零规则中std::vector阅读所有内容


推荐阅读