代码之家  ›  专栏  ›  技术社区  ›  Galaxy

为什么在初始化时不调用重载的赋值运算符?[副本]

  •  -3
  • Galaxy  · 技术社区  · 7 年前

    这个问题已经有了答案:

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

    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 回复  |  直到 7 年前
        1
  •  -4
  •   Galaxy    7 年前

    这是因为初始化与赋值不同。因此不会调用重载赋值运算符。在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