UE4智能指针TSharedPtr的几种初始化方式

23 篇文章 12 订阅

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 <typename InObjectType, ESPMode InMode = ESPMode::Fast, typename... InArgTypes>
FORCEINLINE TSharedRef<InObjectType, InMode> 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<T> MakeShareable( T* ptr);

template <typename T, ESPMode InMode = ESPMode::Fast, typename... InArgTypes>
TSharedRef<T, InMode> MakeShared(InArgTypes&&... Args)

可以看出,它们主要有如下几点不同

  • 返回值不同。MakeShareable返回Proxy,将用Proxy去调用TSharePtr构造函数;MakeShared返回TSharedRef,将用TSharedRef去调用TSharedPtr构造函数。
  • 参数不同。MakeShareable参数是T*,MakeShared的参数是T的构造函数参数。
  • 函数名不同:D

使用时,它们的形式如下

TSharedPtr< float, Mode > FloatRef = MakeShareable( new float( 123.0f ) );
TSharedPtr< float, Mode > FloatRef = MakeShared(123.0f);

如果目标类的构造函数是private的,则只能使用MakeShareable,如果构造函数是public的,则使用哪个都行,看个人喜好和习惯了。至于MakeShared性能略高这一点,我觉得大多数情况下,这带来不了多大的区别,除非性能优化已经优化到了这一步:D

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值