ref类对象是分配在托管堆上的么?
www.diybl.com 时间 : 2008-08-03 作者:佚名 编辑:本站 点击: [ 评论 ]
今天看网上一片文章强调(出处忘记了),ref类对象的实例,是分配在托管堆上的仍然会被GC。我觉得很别扭,看《pro vc++ cli and .net 2.0 platform》的时候,有一个例子和网上说的十分相似,代码如下:
ref class RefClass {};
RefClass^ ERRORexample()
{
RefClass a;
// do some stuff;
return %a;
}
作者认为返回局部对象a的引用是无效的,这一点和传统C++返回局部对象的指针一样,将造成内存泄露;这样理解是比较清楚的,但是根据网上那篇文章的观点,认为实际上ref类对象也是分配在托管堆上的,并将被GC回收。文章还举了一个和上面程序一样的例子,经我在2005下运行的结果,的确只有警告,但是程序正确的被运行了。
那么,ref类对象究竟是分配在托管堆上的还是栈上的呢?
我写了以下程序,来尝试求证这个问题:
using namespace System;
ref class RefClass
{
public:
int _x;
RefClass(int x):_x(x)
{
}
RefClass(const RefClass% other)
{
_x = other._x;
Console::WriteLine("copying");
}
~RefClass()
{
Console::WriteLine("died");
}
};
RefClass% foo()
{
RefClass a(10);
return a;
}
RefClass^ foo2()
{
RefClass^ a = gcnew RefClass(11);
return a;
}
int main(array<System::String ^> ^args)
{
RefClass r = foo();
Console::WriteLine(r._x);
RefClass^ r2 = foo2();
Console::WriteLine(r2->_x);
return 0;
}
结果程序运行的结果是:
died 这行表明foo中return a之后,局部对象被析构了
copying 这是拷贝构造函数得到了执行
10
11 通过gcnew创建的对象句柄,并没有因为函数的结束被析构
died 最终程序结束时,给GC销毁
由此可见
ref类对象,也应该理解为分配在栈上的。
理由:
1 因其在函数结束时,被立即析构了
2 根据《pro vc++ cli and .net 2.0 platform》的提示,不应该把局部的ref类对象的引用作为函数返回值
唯一的疑惑:
vs 2005居然默许了前一个例子的运行,而只是给出警告,运行却是正确的。