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 已经指向的相同内存单元,还是我错过了什么?

4

2 回答 2

1

这是因为 p2 设法分配 p1 已经指向的相同内存单元,还是我错过了什么?

你什么都没错过。您已正确确定该程序的行为是undefined。根据定义,它可以打印任何东西,包括2.

在您的运行中,只有巧合(并且很可能是您确定的巧合)导致它打印2new int(47)您可能会通过在现有的之后delete和之前添加来破坏该巧合链new

如果您希望程序按照它的方式运行,但通过定义的行为,您可以对bar's 的定义进行以下小的更改:

void
bar(Foo*& p2)

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

于 2012-07-14T02:01:03.973 回答
0

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

于 2012-07-14T16:31:32.167 回答