std::shared_ptr<Type> 和 Type^ 之间的区别

Difference between std::shared_ptr<Type> and Type^

本文关键字:Type 之间 区别 gt shared lt std ptr      更新时间:2023-10-16

我真的不明白C++/CX中shared_ptr和新句柄表示法(^)之间的区别。从我读到的内容来看,他们在引用计数和内存管理方面似乎做了同样的事情。我错过了什么?

std::shared_ptr<Type>
//vs
Type^

仅考虑寿命管理,它们是相同的:shared_ptr<T>持有对T对象的强(拥有)引用;CCD_ 3也做同样的事情。CCD_ 4与C++/CX中的CCD_。

如果你在任何地方看到T^,你都会想到shared_ptr<T>ComPtr<T>CComPtr<T>,那么没关系——寿命管理大致相同。

不过,生存期管理在后台的工作方式是不同的:T^格式良好的每个T类型都是实现IUnknown接口的Windows运行时引用类型,因此T对象是内部引用计数的(*)shared_ptr<T>支持任意类型并使用外部引用计数(即,它分配自己的引用计数机制来控制对象的生存期)。

对于弱引用,shared_ptr<T>具有weak_ptr<T>T^具有WeakReferenceWeakReference不是强类型的,但你可以很容易地围绕它编写一个强类型引用包装。否则,弱引用会像你期望的那样工作。对弱引用的支持是可选的:不是所有引用类型都支持弱引用,但大多数都支持。

(*)有一个例外:Platform::String^,它不是Windows运行时引用类型,但由于各种原因而被特殊处理。不过,在终身管理方面,您可以将其视为与任何其他T^相同


那么,为什么Windows运行时类型在C++/CX中戴帽子呢?为什么不使用像shared_ptr<T>ComPtr<T>这样的库解决方案?

这是因为你从来没有真正的指向具体运行时类型的指针(或帽子):你只能通过指向其类型实现的接口之一的指针与对象交互。Windows Runtime也不支持接口或类继承:每个接口都必须直接从IInspectable派生,并且类继承是通过使用COM聚合来模拟的。

简言之,没有任何库解决方案可以产生具有静态类型安全性的自然外观的C++代码。函数调用、派生到基的转换和接口转换通常需要调用QueryInterface才能获得正确的接口指针。

您可以使用库解决方案(例如,请参阅WRL库或几乎任何COM代码)来实现这一点,但您不能支持C++语言功能,如隐式转换或dynamic_cast。如果没有帽子,您只能处理接口指针,并且必须自己调用QueryInterface


(如果你对为什么开发C++/CX语言扩展以及C++/CLI语法最终是如何被选择重用感兴趣,我推荐Jim Springfield去年在这个博客上发表的文章"C++/CX设计内幕"。另外值得注意的是GoingNative的第3集,Marian Luparu在其中讨论了C++/CX。)

据我所知,后者缺乏对弱引用和自定义释放函数的支持。

请注意,前者更通用,(原则上)接受任何类型,并且为了安全和清洁,需要使用辅助函数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++,或者将现有的资源管理方案包装为引用计数方案,那么您将需要前者。