为什么这个指针在 g++ 和 visual studio 2022 的编译器之间表现不同?

Why does this pointer behave differently between g++ and visual studio 2022's compiler?

编辑:我的问题与编译器之间的差异有关,但我只是被误导认为存在不同的行为,而实际上两个编译器都显示出预期的“未定义行为”

我知道在这里使用 static 关键字对 building_num 整数有好处,但我不明白为什么在使用 g++ 编译时该值打印正确,我认为应该删除整数值在 assign_building_num 函数终止后

使用 visual studio 的编译器,我看到了我假设的行为,它没有打印出 400,而是打印出一些随机数(在这种情况下,由于某种原因它总是 32759)

#include <iostream>
#include <string>

using namespace std;

class building {
    int* ptr_building_num;

public:
    void set_building_num(int* num_ptr) {
        ptr_building_num = num_ptr;
    }

    void print_building() {
        cout << *ptr_building_num << flush;
    }
};

void assign_building_num(building* building_ptr) {
    //int* ptr_to_building_num = nullptr;
    int building_num = 400;
    int* ptr_to_building_num = &building_num;

    building_ptr->set_building_num(ptr_to_building_num);
}

int main() {
    building* ptr_to_some_building = nullptr;
    ptr_to_some_building = new building;

    assign_building_num(ptr_to_some_building);

    ptr_to_some_building->print_building();

    return 0;
}

范围内声明的变量(在本例中,building_num 的范围是函数 assign_ building_num 的主体)在范围退出后不再存在。

您正在获取生命周期很短的整数的地址,并在对象被销毁后保留其地址。

从指向已销毁对象的指针读取是未定义行为,因此两个编译器都是正确的。

您的建筑对象所在地址的整数必须至少与建筑对象本身一样长

编辑: 由于出现了未定义行为的问题,为了完整起见,这里是 cppreference 所说的:

undefined behavior - there are no restrictions on the behavior of the program. Examples of undefined behavior are data races, memory accesses outside of array bounds, signed integer overflow, null pointer dereference, more than one modifications of the same scalar in an expression without any intermediate sequence point (until C++11)that is unsequenced (since C++11), access to an object through a pointer of a different type, etc. Compilers are not required to diagnose undefined behavior (although many simple situations are diagnosed), and the compiled program is not required to do anything meaningful.

您编写了一些非常非常复杂的代码,最终设置 'building.ptr_building_num' 指向

   void assign_building_num(building* building_ptr) {
    //int* ptr_to_building_num = nullptr;
       int building_num = 400;              <<<<===== this value here
    int* ptr_to_building_num = &building_num;

    building_ptr->set_building_num(ptr_to_building_num);
}

无效。因为一旦该函数结束,该变量就会消失。通常 VS 或 GCC 会就此警告您,但您已经做了足够多的杂耍,以至于他们看不到您正在这样做。

为什么它有时有效而其他时候无效。因为你已经调用了未定义的行为,所以结果可以是任何东西。在我的 VS 系统上我得到了 400。

但是如果我将代码更改为

assign_building_num(ptr_to_some_building);

cout << "test test\n"; <<== add this

ptr_to_some_building->print_building();

然后我得到

test test
-858993460

不清楚你到底想做什么。如果您希望构建指向一个整数(为什么?),那么您需要将该整数分配到某个稳定的地方。

你提示'static',这肯定有效

void assign_building_num(building* building_ptr) {
    //int* ptr_to_building_num = nullptr;
    static int building_num = 400; <<<=======================
    int* ptr_to_building_num = &building_num;

    building_ptr->set_building_num(ptr_to_building_num);
}

但这是一件非常奇怪的事情,所有建筑实例最终都会指向同一个整数。也许这就是你想要的。很难说。否则在堆上分配。或者如果它只是一个整数就把它放在建筑对象中