我正在尝试使用指针向量并遇到以下行为,我不太明白:
#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
有没有人对第一个输出有解释?
答案 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;
在g++
输出中,您会看到显示新值200,这是因为它位于
int* p1 = new int;
*p1 = 100;
代码,不要使用该值,因为该行为是特定于实现的,并且它只显示,因为您之前没有分配任何可以放入释放的内存位置的内容。