C++ 分配奇怪的行为

C++ Assignment strange behaviour

本文关键字:分配 C++      更新时间:2023-10-16

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

#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.-阿尔夫和@Mr_Hic的回答!问题是默认的 darr_t::operator= 首先调用基类型的赋值,但之后它为对象的成员调用darr_t赋值(覆盖(!

您正在观察该行为,因为:

  1. 编译器为 darr_t 定义了一个隐式复制赋值运算符。
  2. 隐式复制赋值
  3. 首先调用基类的复制赋值运算符,然后再执行成员变量的复制赋值。

以下是 http://en.cppreference.com/w/cpp/language/as_operator 的相关文档:

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

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

T的每个直接基B都有一个复制赋值运算符,其参数为 Bconst B&const volatile B&

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

否则,隐式声明的复制赋值运算符将声明为 T& T::operator=(T&) 。(请注意,由于这些规则,隐式声明的复制赋值运算符无法绑定到易失性左值参数(

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

你试图拉动的指针魔术并没有按照你的期望去做。 在打印变量之前添加一些行以打印出对象的地址 yield(在我的机器上(:

Address in constructor: 0x7fff56264610
Value in constructor: 56
Address in assignment: 0x7fff56264610
Value in assignment: 56
Address in main: 0x7fff56264618
Value in main: 55