#include <iostream>
#include <string>
using namespace std;
static inline string BoolToString(bool boolean_exp) {
return boolean_exp? "True" : "False";
}
class Foo {
public:
explicit Foo(int _size) noexcept :
my_resource(new int[_size]) {
cout << "Foo obj init, at: " << this << ", my_resource at:" << my_resource <<endl;
my_resource[0] = 1234567;
}
~Foo() {
cout << "A Foo instance at: " << this << " is finalizing; ";
cout << "my_resource: " << my_resource << endl;
delete[] my_resource;
my_resource = nullptr;
}
public:
int *my_resource = nullptr;
};
void function_foo(Foo f) {
cout << "function_foo() invoked" << endl;
}
int main(int argc, char *argv[]) {
Foo foo(20);
function_foo(foo); // I think, foo's copy should released after function_foo() return-ed, my_resource should be nullptr;
cout << "Is foo.my_resource released?: " << BoolToString(foo.my_resource == nullptr) << endl;
cout << (*foo.my_resource) << endl;
return 0;
}
显然,在主函数中调用function_foo
函数后,foo的一个浅拷贝被作为参数传递给function_foo
,并且该浅拷贝应该在function_foo
完成后被解构。函数完成运行后,foo中的my_resource
字段(在主函数中声明)仍然可以解析并获得值1234567,我想知道为什么会这样?
我的想法是,虽然my_resource
指向的内存资源在临时对象被解构时被释放,但该内存资源不会被回收或覆盖,因此它仍然可以在错误的中访问。道路
编译器做了不该做的事吗?
顺便说一下,我使用clang++作为编译器,开发环境是windows。
编译:clang++ file.cxx -o file.exe
运行:./file
结果:
Foo obj init, at: 0x61fdd8, my_resource at:0x1f1e90
function_foo() invoked
A Foo instance at: 0x61fdd0 is finalizing; my_resource: 0x1f1e90
is foo.my_resource released?: False
1234567
A Foo instance at: 0x61fdd8 is finalizing; my_resource: 0x1f1e90
函数运行完成后,foo中的my_resource字段(在主函数中声明)仍然可以被解析并获得值1234567我想知道为什么会这样?
这是一个未定义的行为,所以如果你不走运,它可能会起作用。
在典型的c++实现中,这很有可能不会崩溃,因为分配的内存比页面小,并且不需要分配器将内存返回给操作系统。这意味着您的进程仍然能够读取该地址。
此外,编译器没有决定将该地址用于其他内容,因此恰好该值仍然存在。
内存资源被释放,但这并不意味着它消失了!它只是被标记为"空闲内存"下一次你的程序试图分配内存的时候,它可能会得到那块内存。所以,是的…它还在那儿……现在……但是你不应该依赖它,因为你无法预测它将来会发生什么。
c++不会费心去"锁定访问";或者只是"擦除";释放的内存,因为这只会占用CPU周期,没有任何实际的好处。在你释放了内存之后,无论如何你都不应该再碰它。