我真的不明白在C ++ / CX中shared_ptr和新句柄符号(^)之间的区别。根据我的阅读,他们似乎在引用计数和内存管理方面做同样的事情。我错过了什么?
std::shared_ptr<Type>
//vs
Type^
答案 0 :(得分:12)
仅考虑终身管理,这些是相同的:shared_ptr<T>
拥有对T
对象的强大(拥有)引用; T^
做同样的事。 make_shared<T>
大致相当于C ++ / CX中的ref new T
。
如果到处都有您认为T^
或shared_ptr<T>
或ComPtr<T>
的{{1}},那就没关系 - 生命周期管理大致相同。
生命周期管理的工作原理有所不同:CComPtr<T>
格式正确的每个T
类型都是实现T^
接口的Windows运行时引用类型,因此IUnknown
对象在内部引用计数(*)。 T
支持任意类型并使用外部引用计数(即,它分配自己的引用计数机制来控制对象的生命周期)。
对于弱引用,shared_ptr<T>
有shared_ptr<T>
,weak_ptr<T>
有T^
。 WeakReference
不是强类型的,但您可以轻松地在其周围编写强类型的引用包装。否则,弱引用会像您期望的那样工作。对弱引用的支持是可选的:并非所有引用类型都支持弱引用,但大多数引用类型都支持弱引用。
(*)有一个例外:WeakReference
,它不是Windows运行时引用类型,但由于各种原因而特别处理。但是,您可以将其视为与终身管理方面的任何其他Platform::String^
相同。
那么,为什么Windows运行时类型会在C ++ / CX中戴帽子呢?为什么不使用T^
或shared_ptr<T>
这样的库解决方案?
这是因为你从未真正拥有指向具体运行时类型的指针(或帽子):你只能通过指向其类型实现的接口之一的指针与对象进行交互。 Windows运行时也不支持接口或类继承:每个接口必须直接从ComPtr<T>
派生,并且通过使用COM聚合来模拟类继承。
简而言之,没有库解决方案可以产生具有静态类型安全性的自然外观C ++代码。函数调用,派生到基础的转换和接口转换通常需要调用IInspectable
才能获得正确的接口指针。
您可以使用库解决方案(例如,参见WRL库或几乎任何COM代码)来执行此操作,但您不能支持隐式转换或QueryInterface
等C ++语言功能。如果没有帽子,你就只能处理接口指针而不得不自己打电话给dynamic_cast
。
(如果您对为什么开发C ++ / CX语言扩展以及如何最终选择C ++ / CLI语法以供重用的原因感兴趣,我建议Jim Springfield的帖子在去年的博客上"Inside the C++/CX Design"。另外值得注意的是episode 3 of GoingNative,其中Marian Luparu讨论了C ++ / CX。)
答案 1 :(得分:1)
据我所知,后者缺乏对弱引用和自定义释放函数的支持。
请注意,前者更通用,接受任何类型(原则上),并且为了安全和清洁,需要使用辅助函数make_shared
。后者在语言层面得到支持。这意味着这样的代码在C ++ / CX中是安全的:
some_function(ref new foo(), ref new bar());
在C ++中,你需要这样做:
// bad: if foo is allocated but bar's allocation throws, you leak!
some_function(new foo(), new bar());
// good: both never make it anywhere but into a shared_ptr, no leaks
some_function(make_shared<foo>(), make_shared<bar>());
除此之外,当然,他们实施相同的概念。如果您使用的是C ++ / CX版本,请使用后一种语法以简化和统一;如果您试图坚持使用标准C ++,或者将现有资源管理方案包装到引用计数方案中,那么您将需要前者。