C ++赋值奇怪的行为

时间:2014-06-20 15:30:11

标签: c++ variable-assignment copy-constructor

您能解释一下以下代码的输出吗?变量在赋值结束时改变它的值。

#include <iostream>
#include <new>

using namespace std;

template<class CRTP>
class object_t {
public:
    object_t<CRTP> &operator=(const object_t<CRTP> &a) {
        ((CRTP*)this)->~CRTP();
        new ((CRTP*)this) CRTP(*(const CRTP*)&a);
        cout << "Value in assignment: " << ((CRTP*)this)->n << endl;
        return *this;
    }
};

class darr_t : public object_t<darr_t> {
public:

    int n;

    darr_t(const darr_t &a) : n(a.n + 1) {
       cout << "Value in constructor: " << n << endl;  
    }

    darr_t(int pn) : n(pn) {}
};

int main() {

    darr_t tmp(42);
    darr_t tmp2(55);
    tmp = tmp2;

    cout << "Value in main: " << tmp.n << endl;

    return 0;
}

输出:

  

构造函数中的值:56
  转让价值:56
  主要价值:55

预期产出:

  

构造函数中的值:56
  转让价值:56
  主要价值:56

编辑: 感谢@ Cheersandhth.-Alf和@ Mr_Hic-up的答案! 问题是默认darr_t :: operator =首先调用基类型的赋值,但之后它调用darr_t对象成员的赋值(覆盖)!

2 个答案:

答案 0 :(得分:2)

您正在观察行为,因为:

  1. 编译器为darr_t定义隐式副本赋值运算符。
  2. 隐式复制赋值在执行成员变量的复制赋值之前首先调用基类的复制赋值运算符。
  3. 以下是http://en.cppreference.com/w/cpp/language/as_operator的相关文档:

      

    隐式声明的复制赋值运算符

         

    如果没有为类类型(structclassunion)提供用户定义的副本赋值运算符,则编译器将始终将一个声明为一个内联公共成员班级。如果满足以下所有条件,则隐式声明的复制赋值运算符的格式为T& T::operator=(const T&)

         

    B的每个直接基地T都有一个副本分配运算符,其参数为Bconst B&const volatile B&

         

    类类型的M或类类型数组的每个非静态数据成员T都有一个复制赋值运算符,其参数为Mconst M&或{{ 1}}

         

    否则隐式声明的复制赋值运算符被声明为const volatile M&。 (请注意,由于这些规则,隐式声明的复制赋值运算符无法绑定到volatile lvalue参数)

答案 1 :(得分:0)

    new ((CRTP*)this) CRTP(*(const CRTP*)&a);

你试图拉动的指针魔法并没有达到预期的效果。在打印变量之前添加一些行来打印出对象的地址(在我的机器上):

Address in constructor: 0x7fff56264610
Value in constructor: 56
Address in assignment: 0x7fff56264610
Value in assignment: 56
Address in main: 0x7fff56264618
Value in main: 55
相关问题