注册 登录
编程论坛 C++教室

这代码为什么可以运行呢?

后卿 发布于 2023-04-27 21:49, 580 次点击
程序代码:

#include <iostream>
class hint
{
private:
    char* mem[4]{};
public:
    hint(int val);
    operator int();
    void operator =(int f_gold);
    ~hint();
};
hint::hint(int val)
{
    mem[0] = new char;
    mem[1] = new char;
    mem[2] = new char;
    mem[3] = new char;
    *this = val;
}
hint::~hint()
{
    delete mem[0];
    delete mem[1];
    delete mem[2];
    delete mem[3];
}
hint::operator int()
{
    int val{};
    char* read = (char*)&val;
    read[0] = mem[1][0];
    read[1] = mem[3][0];
    read[2] = mem[2][0];
    read[3] = mem[0][0];
    return  val;
}
void hint::operator=(int val)
{
    char* p = (char*)&val;
    mem[0][0] = p[3];
    mem[1][0] = p[0];
    mem[2][0] = p[2];
    mem[3][0] = p[1];
}
int main()
{
    hint gold{ 100 };
    while (1)
    {
        std::cout << "gold的数量为===>" <<gold;
        system("pause");
        gold = gold + 100;
    }
    system("pause");
}

这代码我脑补了一下过程
最开始,初始化对象gold赋值100,调用了hint(int val),然后hint()调用了operator=(int val),把100拆分赋值给了gold
当<<gold时,进行了类型转换,把gold转成了100进行输出
下面的gold=gold+100
有两种可能性
1.先进行gold+100,将gold转换成了int类型,此时gold成了一个未知的int值,加上100后,赋值给gold
通过下面的代码
程序代码:
void hint::operator=(int val)
{
    char* p = (char*)&val;
    mem[0][0] = p[3];
    mem[1][0] = p[0];
    mem[2][0] = p[2];
    mem[3][0] = p[1];
}

又将这个。。这里说不清了
2.将100转成了hint类型,调用了hint(int val)和operator=(int val),
程序代码:
void hint::operator=(int val)
{
    char* p = (char*)&val;
    mem[0][0] = p[3];
    mem[1][0] = p[0];
    mem[2][0] = p[2];
    mem[3][0] = p[1];
}

又把100打乱了,然后两个hint类型相加、
从以上两点来看,这个程序根本不可能成功啊,为什么它能运行呢??
它的结果反而正是100,200,300,
真的应了这张图了
只有本站会员才能查看附件,请 登录
4 回复
#2
rjsp2023-04-27 23:37
gold = gold + 100;
被翻译成
gold = (int)gold + 100;
也就是
gold.operator=( gold.operator int() + 100 );
#3
后卿2023-04-28 20:59
回复 2楼 rjsp
理解了,非常感谢大佬
#4
后卿2023-04-29 16:25
回复 2楼 rjsp
请问,这段代码的默认复制构造函数是什么样的呢
他们说这段代码,再

hint gold{ 100 };
hint gold1=gold;

这样运行就会出错,是因为复制构造导致了gold和gold1拥有同样内存的mem
而析构却有两次,导致出错
我试了一下吗,并不会出错,奇怪,我的为什么不出错呢?
另外,如果我在后面继续添加代码

gold1=200;

这样,就会调用hint::hint(int val)
这样,就能重新给mem开辟内存,这样的话是不是又避免了这个错误呢

[此贴子已经被作者于2023-4-29 16:30编辑过]

#5
rjsp2023-04-29 18:09
请问,这段代码的默认复制构造函数是什么样的呢
你可以在网上搜索“浅拷贝”这个词(虽然我觉得创造“浅拷贝”/“深拷贝”这两个词是不当的)
基本上相当于memcpy(只是“相当于”,但并不是,因为读取一个未初始化未赋值的变量属于未定义行为,默认的拷贝构造函数也会避开这种未定义行为)。

他们说这段代码
hint gold{ 100 };
hint gold1=gold;
这样运行就会出错,是因为复制构造导致了gold和gold1拥有同样内存的mem
而析构却有两次,导致出错
他们说得对!

我试了一下吗,并不会出错,奇怪,我的为什么不出错呢?
delete两次属于未定义行为。
所谓未定义行为,就是编译器完全不需要负责任的行为。
如果编译器能保证你的代码会出错,或保证你的代码不会出错,那就不属于恐怖的未定义行为了。
简而言之,未定义行为 是一切都不能保证,而不是 保证会出错。

另外,如果我在后面继续添加代码
gold1=200;
这样,就会调用hint::hint(int val)
这样,就能重新给mem开辟内存,这样的话是不是又避免了这个错误呢
不能!
因为你写的 void hint::operator=(int val) 实现代码中并没有重新分配内存
1