在常规C++指针中创建共享指针。MakeShared 会在单个内存块中分配新的对象实例和引用控制器,但要求对象提交公共构造函数。MakeShareable 的效率较低,但即使对象的构造函数为私有,其仍可运行。利用此操作可拥有非自己创建的对象,并在删除对象时支持自定义行为。
引用控制器有两个堆分配。使用 MakeShared 代替 MakeShareable 可避免二次分配,并可提高性能。
int* p = new int(2333);
// 可以通过编译,但不建议用普通指针变量来设置智能指针
TSharedPtr<int> sp(p);
TSharedPtr<int> sp1 = MakeShared<int>(p);
// 若不得已为之,必须在设置后将原来的普通指针置nullptr
p = nullptr;
MakeShared的一个特性是能提升效率。使用MakeShared允许编译器产生更小,更快的代码,产生的代码使用更简洁的数据结构。
shared_ptr<int> ptr(new int());
很明显这段代码需要分配内存,但是它实际上要分配两次。每个TSharedPtr都指向一个控制块,控制块包含被指向对象的引用计数以及其他东西。这个控制块的内存是在TSharedPtr的构造函数中分配的。因此直接使用new,需要一块内存分配给int,还要一块内存分配给控制块。
shared_ptr<int> ptr1 = make_shared<int>();
一次分配就足够了。这是因为smake_shared申请一个单独的内存块来同时存放 int 对象和控制块。这个优化减少了程序的静态大小,因为代码只包含一次内存分配的调用,并且这会加快代码的执行速度,因为内存只分配了一次。另外,使用make_shared消除了一些控制块需要记录的信息,这样潜在地减少了程序的总内存占用。
MakeShared其实返回的是一个TSharedRef,又因为TSharedPtr提供了以TSharedRef为参数的构造函数,所以MakeShared方式的构造原理在于先创建TSharedRef,再用这个TSharedRef去调用TSharedPtr的构造函数
template <typename InObjectType, ESPMode InMode = ESPMode::ThreadSafe, typename... InArgTypes>
FORCEINLINE TSharedRef<InObjectType, InMode> MakeShared(InArgTypes&&... Args)
{
SharedPointerInternals::TIntrusiveReferenceController<InObjectType, InMode>* Controller = SharedPointerInternals::NewIntrusiveReferenceController<InMode, InObjectType>(Forward<InArgTypes>(Args)...);
return UE::Core::Private::MakeSharedRef<InObjectType, InMode>(Controller->GetObjectPtr(), (SharedPointerInternals::TReferenceControllerBase<InMode>*)Controller);
}
MakeShareable其实是构造了一个SharedPointerInternals::FRawPtrProxy< ObjectType >,而TSharedPtr提供了一个以SharedPointerInternals::FRawPtrProxy< ObjectType >为参数的构造函数,如下
template< class ObjectType >
FORCEINLINE SharedPointerInternals::TRawPtrProxy< ObjectType > MakeShareable( ObjectType* InObject )
{
return SharedPointerInternals::TRawPtrProxy< ObjectType >( InObject );
}
MakeShareable接受的参数是一个原生指针,只要你提供指针给它就行,它才不管你构造函数是公有私有的呢!而MakeShared接受的是类的构造函数的参数,它要在内部调用构造函数,如果是构造函数是私有的,MakeShared当然没有权限调用了!
MakeShareable返回Proxy,将用Proxy去调用TSharePtr构造函数;MakeShared返回TSharedRef,将用TSharedRef去调用TSharedPtr构造函数。
MakeShareable参数是T*,MakeShared的参数是T的构造函数参数。