4

我正在尝试使用指针向量并遇到以下我不太了解的行为:

#include <iostream>
#include <vector>

int main()
{
    std::vector<int*> vec;

    int* p1 = new int;
    *p1 = 100;

    vec.push_back(p1);  
    std::cout << *vec[0] << std::endl;

    delete p1;
    std::cout << *vec[0] << std::endl;

    int* p2 = new int;
    *p2 = 200;

    std::cout << *vec[0] << std::endl;

    return 0;
}

使用 MinGW C++ 编译器 (g++),这给了我以下输出:

100
5640648
200

现在当然在删除指针时实际元素vec[0]没有被删除,但请注意p2根本没有插入向量中。尽管如此,打印第一个元素的值会返回这个看似无关的指针的值!此外,稍微重组代码以便p2在删除之前声明p1不会产生这种行为。

为了确保,我还用 MSVC++ 编译了它,它给了我以下(预期的)输出:

100
5484120
5484120

有人对第一个输出有解释吗?

4

5 回答 5

6

因为删除后你访问内存它会导致未定义的行为:

delete p1;
std::cout << *vec[0] << std::endl;  <-- Buggy code

未定义的行为: - 不保证它将如何工作

于 2013-08-01T16:30:01.667 回答
5

它重新分配了仍然指向的空间,因此出现了p1值。 vec[0]200

正如您所注意到的,这是一个编译器的行为,而另一个编译器的行为不同。您可能还有其他基于不同优化开关的行为。所以总的来说,行为是不确定的,尽管我们有时可以弄清楚在特定情况下发生了什么。

于 2013-08-01T16:29:49.993 回答
0

您首先了解为什么这是未定义的行为吗?

vec[0] 值为 p1。只要你删除 p1; 取消引用 vec[0] 是非法的。vec[0] 只是指针 p1 的副本。

想象一下,它的值p1是(地址)953241,由new返回,供你自由使用。您存储在该地址中的 int 值是 100。但是一旦删除 p1,您就放弃了与该地址有关的任何权利。您有效地将其交还给系统。你不能再读它了。

于 2013-08-01T16:39:53.710 回答
0

当你 时delete p1,C++ 会释放p1堆上占用的空间,并让它用于其他数据。因此,当您创建时p2,它会将其放在那里,因为它是它要使用的内存中的下一个位置。

vec[0]仍然指向那里,只是因为您的指针中的数据仍然在堆栈中。(C++ 不知道你删除了指针,但指针数据不会去任何地方,所以你可以访问它。下次你在堆栈上做任何事情时它会被替换。)

我猜 MSVC++ 故意尝试不使用最近释放的内存空间,因为它“更安全”——如果你deleted不小心把它覆盖了,它就永远消失了。

于 2013-08-01T16:40:00.950 回答
0
delete p1;
std::cout << *vec[0] << std::endl; // (1.)

int* p2 = new int;
*p2 = 200;

std::cout << *vec[0] << std::endl; // (2.)

return 0;
  1. 您删除了内存,因此未定义该地址的内容。
  2. g++输出中,您会看到显示了新值 200,这是因为它位于

    int* p1 = new int;
    *p1 = 100;
    

    代码,不要使用该值,因为该行为是特定于实现的,并且它仅显示是因为您没有更早地分配任何可以放入已释放内存位置的东西。

于 2013-08-01T16:40:03.187 回答