C++ C++;奇怪的行为

C++ C++;奇怪的行为,c++,variable-assignment,copy-constructor,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)

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

#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;
}
#包括
#包括
使用名称空间std;
模板
类对象{
公众:
对象\u t&运算符=(常量对象\u t&a){
((CRTP*)这个)->~CRTP();
新的(CRTP*)本CRTP(*(常数CRTP*)&a);
库特
你尝试使用的指针魔法并没有达到你期望的效果。在打印变量之前(在我的机器上),添加一些行来打印对象的地址:


您观察该行为是因为:

  • 编译器为
    darr\u t
    定义隐式复制赋值运算符
  • 隐式复制赋值在执行成员变量的复制赋值之前,首先调用基类的复制赋值运算符
  • 以下是来自以下网站的相关文档:

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

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

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

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

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


    代码的目的是什么。也许我们可以建议更好的方法来做任何事情。结果是:您使用的是默认的darr_t::operator=。它不会做任何花哨的事情。因此您会得到非花哨的结果。这看起来像是家庭作业。我一辈子都无法想象有人会编写这样的代码。几乎所有的事情都出了问题。如果不是家庭作业,请不要这样做。至少不要在其他人必须维护的代码中这样做。手动调用析构函数是不安全的。如果下一行的新运算符中出现异常,则对象处于未定义状态。@Barricadenick:请阅读生成的赋值运算符的功能。尝试生成它如编译器所做的那样,用手工来查看。这是否帮助您理解这个?“操作符=”不是子类继承的。这是C++标准的一部分。执行赋值运算符代码有点奇怪。按照我的理解,编译器只需调用基类的赋值运算符,然后执行当前的类运算符。但正如Cheers和hth-Alf所提到的,编译器生成一个会盲目复制属性的运算符。因此,这可能就是值随后被带到bac的原因k至“55”。
        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