2012-07-14 251 views
0

请看下面的例子传递一个指针作为参数传递给函数

class Foo{ 
    public: 
    Foo(int i):x(i){} 
    int x; 
}; 

void 
bar(Foo *p2) 
{ 
    delete p2; 
    p2 = new Foo(2); 
} 

int 
main() 
{ 
    Foo *p1 = new Foo(1); 
    cout<<p1->x; 
    bar(p1); 
    cout<<p1->x; 
} 

据我了解,指针变量都保存在栈上,并包含一个地址在堆上动态分配的内存,它的“指点”至。现在,当我传递一个指向该函数的指针时,第二个指针将在堆栈上创建,指向与第一个指针相同的内存地址。当我删除bar()中的p2并分配新内存时,p1和p2应该指向不同的地址,对吧?

但是,如果我编译此代码,我得到1和2作为输出。这是因为P2设法分配与P1已经指向的相同的存储单元,还是有我错过的东西?

+0

修复这个错误,这个谜将消失。 – 2012-07-14 02:09:31

回答

1

这是因为p2设法分配与p1已经指向的存储单元相同的存储单元,还是有我遗漏的某些内容?

你没有遗漏任何东西。您已经正确识别出该程序的行为是undefined。根据定义,它可以打印任何东西,包括2

在你的跑步中,它只是巧合(很可能是你识别的巧合),导致它打印2。您可能会在delete之后和现有new之前添加new int(47),从而中断该巧合链。

如果你的愿望是该程序的行为它的方式,而是通过定义行为,你可以让这个小改动bar的定义:

void 
bar(Foo*& p2) 

这一引用传递参数而不是的价值。通过这样做,对bar内变量p2的更改反映在p1内部的main中。

+0

Yupp,打印出1和47.谢谢。 – Carlj901 2012-07-14 02:10:57

+1

我认为可能值得一提的是,OP可以通过将'bar'的参数改为'Foo *&'来获得他们想要的行为(假设代码的意图与问题本身的意图不同)。 – ildjarn 2012-07-14 02:25:27

+0

优秀点,@ildjarn。我补充说。 – 2012-07-14 02:57:02

0

除了你的示例中,指针变量不一定在堆栈上,它们引用的地址不一定在堆上(但new和malloc都返回堆中的地址)。指针变量和它引用的地址都可以在堆栈,堆,全局/静态变量区域,甚至ROM中。其余的解释是正确的,但你观察到的行为是不确定的,期望它是可重复的,这确实是非常危险的。任何更改,不同的运行时版本,多线程情况,不同体系结构或其他编译器的编译都可以完全改变结果:随机值或崩溃。