2011-04-02 108 views
1

编写下面的代码后:C++公共构造地址

#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没有释放任何空间其他空间。为什么?

+1

在键盘上:http://codepad.org/boErRgnM它给出了'节点(i)'是临时的警告。也许你应该坚持'新节点(i)' – quasiverse 2011-04-02 23:14:06

+0

我错误地写了这个 – 2011-04-02 23:14:58

+2

后,我只是想知道避免问题的最好办法是确保你的代码编译0警告。警告在技术上是有效的,但几乎总是会导致问题的编程错误。您应该**始终**确保没有警告(并尽可能高地转动警告)。 – 2011-04-03 00:04:00

回答

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

为什么我们动态分配节点对象?更好的解决方案是有一个Node对象数组而不是Node指针数组。 – 2011-04-02 23:50:19

+0

@Martin对于这个有限的代码示例也是一种可能性(并且对于这个代码示例来说更好,但是我会建议只是摆脱'Node'结构,只是打印1到10的数字),但是'Node '像这样的结构通常用在树或列表结构中,其中'Node'将被大量交换并且交换地址比实际结构快得多。 – user470379 2011-04-03 02:14:44

5

要创建新对象,请使用new Node(i)否则,您正在堆栈上创建临时对象,这就是为什么它们都是相同的。

请记得在新的对象上调用delete。

+0

但为什么所有这些临时对象都具有相同的地址? – 2011-04-02 23:17:07

+1

@The GiG只是巧合。编译器恰好在这种情况下做到了这一点。 – quasiverse 2011-04-02 23:19:02

+1

@The GiG,每个对象在您获取地址后立即销毁。因此,该空间可用于下一个对象。因此它最终重新使用空间。你不能依赖那个,但那可能是这里发生的事情。 – 2011-04-02 23:20:09

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 NodeAlways使用容器对象来管理一组具有相似语义的对象。如果你有,你可以在这里使用std::vector,或者使用std::array。由std::vector引入的开销将小于new引入的开销。

+1

+1最佳答案。考虑到你应该在99%的时间内使用对象(特别是像Node这样简单的事情)。 – 2011-04-03 00:00:15