C++ cli C+中的RAII+/CLI 我习惯了C++的RAI设施,我想在C++和CLI中使用RIIE和托管代码。他们都告诉我这是最好的做法
我有这样的想法:C++ cli C+中的RAII+/CLI 我习惯了C++的RAI设施,我想在C++和CLI中使用RIIE和托管代码。他们都告诉我这是最好的做法,c++-cli,smart-pointers,C++ Cli,Smart Pointers,我有这样的想法: ref struct Managed { // No default constructor Managed( /*...*/ ) { /*...*/ } ~Managed() { /* Important non-managed resource release here */ } // ... }; ref struct UsesManaged { Managed^ m_; array<Managed^
ref struct Managed
{
// No default constructor
Managed( /*...*/ ) { /*...*/ }
~Managed() { /* Important non-managed resource release here */ }
// ...
};
ref struct UsesManaged
{
Managed^ m_;
array<Managed^>^ a_;
UsesManaged( Managed^ m, array<Managed^>^ a ) : m_(m), a_(a) {}
// ...
};
ref struct Creator
{
Managed^ m_;
array<Managed^>^ a_;
UsesManaged^ u_;
Creator()
{
// Must allocate dynamically here, not in initializer list
// because in my real code, I use "this" here for a callback.
m_ = gcnew Managed( /*...*/ );
a_ = gcnew array<Managed^>( 2 );
a_[ 0 ] = gcnew Managed( /*...*/ );
a_[ 1 ] = gcnew Managed( /*...*/ );
u_ = gcnew UsesManaged( m_, a_ );
}
};
ref结构管理
{
//没有默认构造函数
托管(/*…*/){/*…*/}
~Managed(){/*此处发布了重要的非托管资源*/}
// ...
};
ref struct UsesManaged
{
管理^m;
数组^a;
UsesManaged(托管^m,数组^a):m(m),a(a){
// ...
};
引用结构创建者
{
管理^m;
数组^a;
使用托管^u;
创建者()
{
//必须在此处动态分配,而不是在初始值设定项列表中
//因为在我的真实代码中,我在这里使用“this”作为回调。
m_u=gcnew Managed(/*…*/);
a=新阵列(2);
a_u0]=gcnew Managed(/*…*/);
a_u[1]=gcnew-Managed(/*…*/);
u_uu=gc管理的新用途(m_u,a_u);
}
};
我希望(1)自动销毁资源,这样我就不必手动删除每个新对象,尤其是在遇到异常时;(2) 安全、清晰地共享对象的能力(传递std::auto_ptr等不符合条件);(3)让VB或C#使用我的类,并在对象超出范围(例如,由于异常)时自动运行清理功能
标准C++中,我使用STD::SysDypPTR和STD::向量或类似的工具来自动化RAII。在这里,我可以使用STL/CLI的向量,但没有与之等效的共享ptr。我看到的唯一相关的C++/CLI智能指针是,它类似于std::auto_ptr,包括所有权转移语义,它与向量不兼容,尽管它们在数组中可以正常工作
要实现我的三个目标,正确的C++/CLI方法是什么?(另外请注意,我的主C++/CLI类(上面的Creator)将被VB/C#使用。)[更新:在顶部添加了Herb Sutter和MS的链接,并添加了目标3(VB/C#的消费量)。]您可以使用带有托管代码的RAII:如果您有此功能:
ref class A {
~A() { // implements/overrides the IDisposable::Dispose method
// free managed and unmanaged resources here
}
};
void foo()
{
A a(cons_args); // stack-like usage
// use a ...
}
然后您可以这样做:
ref class A {
~A() { // implements/overrides the IDisposable::Dispose method
// free managed and unmanaged resources here
}
};
void foo()
{
A a(cons_args); // stack-like usage
// use a ...
}
这将被有效地视为:
void foo()
{
try
{
A^ a_ = gcnew A(cons_args);
}
finally
{
a_->~A();
}
}
未测试,但这应该让您开始:
template<typename T>
value class counted_handle
{
ref struct Count { int refCount; Count() : refCount(1) {} };
T^ m_sharedHandle;
Count^ m_sharedCount;
void release() { if (m_sharedCount && 0 == --sharedCount->refCount) delete m_sharedHandle; m_sharedCount = nullptr; m_sharedHandle = nullptr; }
void addref( if (m_sharedCount) ++m_sharedCount->refCount; }
public:
counted_handle() : m_sharedHandle(nullptr), m_sharedCount(nullptr) {}
counted_handle(T^ handle) : m_sharedHandle(handle), m_sharedCount(gcnew Count()) {}
counted_handle(counted_handle<T>% src) : m_sharedHandle(src.m_sharedHandle), m_sharedCount(src.sharedCount) { addref(); }
void ~counted_handle() { release(); }
counted_handle<T>% operator=(counted_handle<T>% src) { src.addref(); release(); m_sharedHandle = src.m_sharedHandle; m_sharedCount = src.m_sharedCount; }
counted_handle<T>% operator=(T^ handle) { release(); m_sharedHandle = handle; m_sharedCount = gcnew Count(); }
}
模板
值类\u句柄
{
ref结构计数{int refCount;Count():refCount(1){};
T^m_sharedHandle;
计数^m\u共享计数;
void release(){如果(m_sharedCount&&0==--sharedCount->refCount)删除m_sharedHandle;m_sharedCount=nullptr;m_sharedHandle=nullptr;}
void addref(如果(m_sharedCount)++m_sharedCount->refCount;}
公众:
counted_handle():m_sharedHandle(nullptr),m_sharedCount(nullptr){}
已计数的句柄(T^handle):m_sharedHandle(句柄),m_sharedCount(gcnew Count()){
计数句柄(计数句柄%src):m_sharedHandle(src.m_sharedHandle),m_sharedCount(src.sharedCount){addref();}
void~counted_handle(){release();}
计数的\u句柄%operator=(计数的\u句柄%src){src.addref();release();m_sharedHandle=src.m_sharedHandle;m_sharedCount=src.m_sharedCount;}
已计数的句柄%operator=(T^handle){release();m_sharedHandle=handle;m_sharedCount=gcnew Count();}
}
我认为我的问题的正确答案是由准答案对其他人答案的评论:
啊,你不能那样做。没有
强制垃圾收集器
摧毁一个物体。看到了吗
正确的方法是要求
一个明确的结束通话
在终结器中调用它。如果
客户机代码不可用的某些原因
清理,总承包商将(最终)
为您清理(在程序中)
终止协议(如果没有其他),但您
无法编写依赖于的代码
-比利·奥尼尔9月10日10点10分
16:02
除了他给出的链接,另请参见和。+1,是的,这是一种方法。我非常不喜欢这种语法,它是一个主要的错误生成器,让新手几乎没有机会猜测他们何时必须使用插入符号。但就这样吧。+1--但我仍然认为任何人都需要正确阅读,但正如我在Creator's的评论中所暗示的那样s构造函数,我必须使用动态分配而不是“GC堆栈”分配。我真正需要的是一个相当于std::shared_ptr的C++/CLI。@mclimber:啊——你不能这么做。没有办法强迫垃圾收集器销毁对象。请看正确的方法,那就是要求显式关闭调用,并在终结器中对此进行调用。如果出于某种原因,客户端代码没有清理,GC将(最终)为您清理(在程序终止时,如果没有其他的东西),但是您不能编写依赖于C++的代码。@比利:您不能有确定性的解除分配,但可以有确定性的处理。当父对象被释放时(或对于本地对象,当作用域结束时),会自动调用。它肯定可以实现一个
自动句柄
变量(计数句柄
?)它的行为类似于std::shared_ptr
,但我认为Microsoft没有提供。严格来说,这不是RAII,因为您使用的是分配,而不是初始化来获得资源的所有权。它是一个智能指针,与RAII共享很多。IDisposable接口是托管代码中一个成熟的模式。但是您确实还必须包含终结器,以便自动释放资源。Add!Managed()。Hans,我想您可能已经删除了关于此问题的较长答案。这很有帮助,我希望您留下它,以便我们可以在那里讨论。