删除向量中的指针后出现意外行为

时间:2013-08-01 16:26:21

标签: c++ pointers vector

我正在尝试使用指针向量并遇到以下行为,我不太明白:

#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

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

5 个答案:

答案 0 :(得分:6)

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

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

未定义的行为: - 无保证如何运作

答案 1 :(得分:5)

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

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

答案 2 :(得分:0)

您是否首先理解为什么这是未定义的行为

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

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

答案 3 :(得分:0)

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

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

我猜测MSVC ++有目的地试图不使用最近释放的内存空间,因为它“更安全” - 如果你偶然发现deleted然后覆盖了它,它就会永远消失。

答案 4 :(得分: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;
    

    代码,不要使用该值,因为该行为是特定于实现的,并且它只显示,因为您之前没有分配任何可以放入释放的内存位置的内容。