-3

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

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字段是相同的。它应该是不同的。似乎调用了默认赋值运算符。我不知道为什么会这样。

不要试图批评程序本身。这只是出于教育目的的测试。我故意设置了这个,这样我就有了一个双重免费的错误。重载的赋值运算符旨在防止这种情况。它没有通过第二次测试......为什么会这样?

4

1 回答 1

-4

这是因为初始化与赋值不同。所以重载的赋值运算符没有被调用。复制构造函数在 Main 2 中被调用。因为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;
}

输出如预期:

copy constructor called
id  = 2
val = 15
ptr = 0xea4c40
*ptr = 10

id  = 1
val = 15
ptr = 0xea4c20
*ptr = 10
于 2018-10-14T21:44:19.553 回答