1、一个指向空指针的TSharedPtr
TSharedPtr< bool, Mode > MyEmptyBoolPtr;
2、 直接使用原生指针构造
TSharedPtr< int32, Mode > MyIntSharedPtr( new int32( 123 ) );
int* Foo = new int32( 123 );
TSharedPtr< bool, Mode > MyIntSharedPtr( Foo );
需要注意的是,使用原生指针的构造函数是explicit的,意味着不能进行隐式构造,只能显式构造
//错误!不能隐式调用构造函数!
TSharedPtr< float, Mode > FloatPtr = new float( 123.0f );
3、使用别的TSharedPtr拷贝构造。
TSharedPtr< bool, Mode > FirstBoolRef( new bool( false ) );
TSharedPtr< bool, Mode > SecondBoolRef( FirstBoolRef );
TSharedPtr< bool, Mode > ThiredBoolRef = FirstBoolRef;//效果同上
4、使用别的TSharedRef构造。
TSharedRef< int32, Mode > MySharedRef( new int32( 1 ) );
TSharedPtr< int32, Mode > MySharedPtr( MySharedRef );
能够这样做的原因在于TSharedPtr提供了以TSharedRef为参数的构造函数,源码如下
FORCEINLINE TSharedPtr( TSharedRef< OtherType, Mode > const& InSharedRef )
: Object( InSharedRef.Object )
, SharedReferenceCount( InSharedRef.SharedReferenceCount )
{
// There is no rvalue overload of this constructor, because 'stealing' the pointer from a
// TSharedRef would leave it as null, which would invalidate its invariant.
}
5、通过TWeakPtr构造
//这里WeakInt是一个TWeakPtr< int32, Mode >
TSharedPtr< int32, Mode > SharedInt( WeakInt.Pin() );
这个方法的原理在于TWeakPtr::Pin返回了一个TSharedPtr,然后用这个TSharedPtr去进行拷贝构造。
6、使用MakeSharable构造。
TSharedPtr< float, Mode > FloatPtr = MakeShareable( new float( 30.0f ) );
MakeShareable源码如下
template< class ObjectType >
FORCEINLINE SharedPointerInternals::FRawPtrProxy< ObjectType > MakeShareable( ObjectType* InObject );
我们可以发现,MakeShareable其实是构造了一个SharedPointerInternals::FRawPtrProxy< ObjectType >,而TSharedPtr提供了一个以SharedPointerInternals::FRawPtrProxy< ObjectType >为参数的构造函数,如下
FORCEINLINE TSharedPtr( SharedPointerInternals::FRawPtrProxy< OtherType > const& InRawPtrProxy )
: Object( InRawPtrProxy.Object )
, SharedReferenceCount( InRawPtrProxy.ReferenceController )
{
...
}
这个构造函数支持隐式转换,所以
TSharedPtr< float, Mode > FloatPtr = MakeShareable( new float( 30.0f ) );
这行代码的本质是先构造一个临时变量,然后再用临时变量构造TSharedPtr。
7、使用MakeShared构造。
TSharedPtr< float, Mode > FloatPtr = MakeShared(30.f);
注意,MakeShared的参数是目标类型构造函数的参数。MakeShared源码如下
template
FORCEINLINE TSharedRef MakeShared(InArgTypes&&... Args);
可以看出,MakeShared其实返回的是一个TSharedRef,又因为TSharedPtr提供了以TSharedRef为参数的构造函数,所以MakeShared方式的构造原理在于先创建TSharedRef,再用这个TSharedRef去调用TSharedPtr的构造函数,到这里就与第5条方法一致了。
至此,TSharedPtr的几种初始化方式列举完毕。
介绍完基本的初始化方式后,还有几个有趣的问题值得进一步探讨一下。
Q、官方文档有这么一段描述:
Creates a Shared Pointer from a regular C++ pointer.
MakeShared
allocates a new object instance and the reference controller in a single memory block, but requires the object to offer a public constructor.MakeShareable
is less efficient, but works even if the object's constructor is private, enables you to take ownership of an object you didn't create, and supports customized behaviour when deleting the object.
为什么说MakeShared比MakeShareable效率高?
A:我曾在文章关于C++11中的make_shared
里面探讨过std::make_shared的详细原理,这里的原因也类似, 一次申请肯定比两次申请效率高嘛!
2、如果类的构造函数是私有的,那么只能用MakeShareable不能用MakeShared,为什么?
A:原因很简单,MakeShareable接受的参数是一个原生指针,只要你提供指针给它就行,它才不管你构造函数是公有私有的呢!而MakeShared接受的是类的构造函数的参数,它要在内部调用构造函数,如果是构造函数是私有的,MakeShared当然没有权限调用了!
3、看起来MakeShared和MakeShareable都能用来创建TSharePtr,那么具体使用的时候到底该使用哪个呢?
A:我们先把它们的参数和返回值用伪代码列一下,
template< class T>
SharedPointerInternals::FRawPtrProxy MakeShareable( T* ptr);
template
TSharedRef MakeShared(InArgTypes&&... Args)
可以看出,它们主要有如下几点不同
使用时,它们的形式如下
TSharedPtr< float, Mode > FloatRef = MakeShareable( new float( 123.0f ) );
TSharedPtr< float, Mode > FloatRef = MakeShared(123.0f);
如果目标类的构造函数是private的,则只能使用MakeShareable,如果构造函数是public的,则使用哪个都行,看个人喜好和习惯了。至于MakeShared性能略高这一点,我觉得大多数情况下,这带来不了多大的区别,除非性能优化已经优化到了这一步:D