为什么在初始化时未调用我的重载赋值运算符?

时间:2018-10-14 21:40:23

标签: c++ operator-overloading assignment-operator double-free

我创建了一个测试类来演示重载赋值运算符的用法以及与双重释放内存相关的陷阱。此类的代码如下:

class Test {
  public:
    Test() : ptr{new int(0)}, val{0}, id{count++} {}

    Test(int ptr_val, int new_val) : ptr{new int(ptr_val)}, val{new_val}, id{count++} {}

    ~Test()
    {
        delete ptr;
    }

    Test& operator=(const Test& rhs)
    {
        *ptr = *(rhs.ptr);
        val = rhs.val;
    }

    void setPtrVal(int ptr_val)
    {
        *ptr = ptr_val;
    }

    void setVal(int new_val)
    {
        val = new_val;
    }

    void printData() const
    {
        cout << "id  = " << id  << endl;
        cout << "val = " << val << endl;
        cout << "ptr = " << ptr << endl;
        cout << "*ptr = " << *ptr << endl << endl;
    }
  private:
    int* ptr;
    int val;
    int id;

    static int count;
};

int Test::count = 1;

我有两个主要功能,它们正在使用重载的赋值运算符来测试此类。我将每个主要功能的输出直接放在其主体下方。

主要1:

int main()
{
    Test t1;
    Test t2(2, 2);

    t1.printData();
    t2.printData();

    t2 = t1;  // Overloaded Assignment Operator
    t1.printData();
    t2.printData();

    t2.setVal(3);
    t2.setPtrVal(3);

    t1.printData();
    t2.printData();

    return 0;
}

输出1 :(按预期工作)

id  = 1
val = 0
ptr = 0x204dc20
*ptr = 0

id  = 2
val = 2
ptr = 0x204dc40
*ptr = 2

id  = 1
val = 0
ptr = 0x204dc20
*ptr = 0

id  = 2
val = 0
ptr = 0x204dc40
*ptr = 0

id  = 1
val = 0
ptr = 0x204dc20
*ptr = 0

id  = 2
val = 3
ptr = 0x204dc40
*ptr = 3

主要2:

int main()
{
    Test t1(10, 15);

    {
        Test t2 = t1;
        t2.printData();
    }

    t1.printData();

    return 0;
}

输出2(无法正常工作):

id  = 1
val = 15
ptr = 0xd6fc20
*ptr = 10

id  = 1
val = 15
ptr = 0xd6fc20
*ptr = 0

*** Error in `./a.out': double free or corruption (fasttop): 0x0000000000d6fc20 ***

这很奇怪。由于某种原因,指针指向相同的内存,并且id字段是相同的。它应该是不同的。似乎已调用默认赋值运算符。我不知道为什么会这样。

不要试图批评程序本身。这只是出于教育目的的测试。我是故意设置这个的,所以我会有一个双重免费的错误。重载的赋值运算符旨在防止这种情况。并且第二次测试失败了……为什么这么做?

1 个答案:

答案 0 :(得分:-4)

这是因为初始化与赋值不同。因此,不会调用重载的赋值运算符。在Main 2中将调用复制构造函数。由于此command-line没有定义重载的复制构造函数,因此将使用默认的复制构造函数,它会进行逐成员复制。

我将通过添加副本构造函数进行演示:

class Test

输出符合预期:

class Test {
  public:
    Test() : ptr{new int(0)}, val{0}, id{count++} {}

    Test(int ptr_val, int new_val) : ptr{new int(ptr_val)}, val{new_val}, id{count++} {}

    ~Test()
    {
        delete ptr;
    }

    Test(const Test& rhs) : ptr{new int( *(rhs.ptr)  )}, val{rhs.val}, id{count++}
    {
        cout << "copy constructor called" << endl;
    }

    Test& operator=(const Test& rhs)
    {
        *ptr = *(rhs.ptr);
        val = rhs.val;
    }

    void setPtrVal(int ptr_val)
    {
        *ptr = ptr_val;
    }

    void setVal(int new_val)
    {
        val = new_val;
    }

    void printData() const
    {
        cout << "id  = " << id  << endl;
        cout << "val = " << val << endl;
        cout << "ptr = " << ptr << endl;
        cout << "*ptr = " << *ptr << endl << endl;
    }
  private:
    int* ptr;
    int val;
    int id;

    static int count;
};

int Test::count = 1;


int main()
{
    Test t1(10, 15);

    {
        Test t2 = t1;
        t2.printData();
    }

    t1.printData();

    return 0;
}