编写下面的代码后:
#include <iostream>
using namespace std;
typedef struct Node {
int value;
Node(int index) {
value = index;
}
} Node;
int main() {
Node* arr[10];
for(int i = 0; i < 10; i++) {
arr[i] = &Node(i);
}
for(int i = 0; i < 10; i++)
cout << arr[i]->value << endl;
}
我看到代码只打印了9个而不是0到9之间的所有数字。
在调试代码之后,我看到每个i的arr [i]的地址是相同的,并且Node(i)只为arr [i]释放了一次空间,之后唯一的是它value = index
没有释放任何其他空间。为什么呢?
答案 0 :(得分:6)
这一行:arr[i] = &Node(i);
正在存储指向临时对象的指针。 Node(i)
创建一个临时对象,可以在语句结束时对其进行破坏,此时对它的所有引用都将变为无效,这意味着解除引用arr[i]
的任何代码的结果都将是未定义的。在这种情况下你得到所有9的原因是因为编译器正在优化代码 - 因为一次只创建了1个临时Node(i)
,编译器只是每次循环时重用该内存。
要解决此问题,请为堆中的每个对象分配内存:arr[i] = new Node(i);
。然后,当您完成使用它们时,您还需要记住删除每一个:
for (int i=0; i < 10; ++i) {
delete arr[i];
}
如果您想进一步调查,请尝试在Node
类中添加一些代码以查看正在发生的事情:例如,在构造函数中打印出this
的地址,和/或创建一个析构函数只是打印一条消息,这样你就可以看到它被调用了。
答案 1 :(得分:5)
要创建新对象,请使用new Node(i)
,否则您将在堆栈上创建临时对象,这就是它们完全相同的原因。
请记住在从新回来的每个对象上调用delete。
答案 2 :(得分:3)
&Node(i)
此表达式创建临时变量并返回其地址。然后销毁临时表,并在下次计算表达式时,在同一个地方创建另一个临时表 - 因此地址相同。
您应该可以消除指针的使用,并为Node引入默认值。
#include <iostream>
using namespace std;
typedef struct Node {
int value;
Node(int index) {
value = index;
}
Node() : value( 0 ) {} // allow default construction
} Node;
int main() {
Node arr[10]; // default-construct array values
for(int i = 0; i < 10; i++) {
arr[i] = Node(i);
}
for(int i = 0; i < 10; i++)
cout << arr[i].value << endl;
}
不要单独为每个对象使用new Node
。 始终使用容器对象来管理具有类似语义的一组对象。您可以在此处使用std::vector
,如果您拥有std::array
,则可以使用std::vector
。 new
引入的开销将小于{{1}}引入的开销。