在循环中初始化结构时,为什么地址总是相同的?

When initializing a struct in a loop, why is the address always the same?

在c++17中,我想初始化一个结构体10次,并将引用它们的ptr压入堆栈。而我的代码如下所示。

struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};

stack<TreeNode*> s;
for (int i = 0; i <= 9; i++) {
    TreeNode node(i);
    s.push(&node);
    cout << &node << endl;
}

然而,当我打印我在每个循环中初始化的结构体的地址时,所有的地址都是一样的。

0000003F439BFBA8
0000003F439BFBA8
0000003F439BFBA8
0000003F439BFBA8
0000003F439BFBA8
0000003F439BFBA8
0000003F439BFBA8
0000003F439BFBA8
0000003F439BFBA8
0000003F439BFBA8

这样,就相当于下面的代码

stack<TreeNode*> s;
TreeNode node(-1);
for (int i = 0; i <= 9; i++) {
    node.val = i;
    s.push(&node);
    cout << &node << endl;
}

我知道在c++中,new用于为堆上的对象分配新的内存块。但是我还是不明白为什么地址是一样的。

如果你能帮助我或给我一些参考,我将不胜感激。

那里发生的事情是 C++ 足够聪明,可以在循环中只初始化一次局部变量。因为它是一个局部变量,所以它使用相同的内存地址,当 node 被初始化时,C++ 分配 node 的内存地址,然后当 C++ 检查 node 是否被初始化时,它有已分配内存并跳过该步骤。

如果保留该代码,您可能 运行 会遇到问题,因为您将本地变量的地址推入 s,但如果 s 不在其中会发生什么功能? s 将继续存在,但您推送的元素是函数的本地元素,因此在函数外部 s 将以未初始化的元素结束。

你需要做的是创建一个指针,使用new分配更多内存,初始化指针然后压入指针。

TreeNode* Node = new TreeNode;
s.push(Node);

C++ 在循环的每次迭代中构造 TreeNode node。但它也通过在每个循环结束时调用(隐式)析构函数来解构 node

这意味着内存可以重复使用。由于示例足够简单,因此在每次循环迭代中确实会重复使用该内存。

如果在没有 delete 的情况下使用 new,则析构函数不会 运行,并且内存不可重用。

cigien的回答很有帮助!但是有一个说法是如果变量只在循环中初始化一次或者在循环中初始化10次。

所以我对代码做了一点改动,是这样的:

struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode(int x) : val(x), left(NULL), right(NULL) {
        cout << x << endl;
    }
};
stack<TreeNode*> s;
for (int i = 0; i <= 9; i++) {
    TreeNode node(i);
    s.push(&node);
    cout << &node << endl;
}

那么,结果是:

0
00000049F28FF518
1
00000049F28FF518
2
00000049F28FF518
3
00000049F28FF518
4
00000049F28FF518
5
00000049F28FF518
6
00000049F28FF518
7
00000049F28FF518
8
00000049F28FF518
9
00000049F28FF518

我想知道这是否表明该结构在每个循环中创建并在每个循环结束时销毁。