• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

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

武飞扬头像
桃溪小小生
帮助5

1、一个指向空指针的TSharedPtr

  1.  
    TSharedPtr< bool, Mode > MyEmptyBoolPtr;
  2.  
     

2、 直接使用原生指针构造

  1.  
    TSharedPtr< int32, Mode > MyIntSharedPtr( new int32( 123 ) );
  2.  
     
  3.  
    int* Foo = new int32( 123 );
  4.  
    TSharedPtr< bool, Mode > MyIntSharedPtr( Foo );

需要注意的是,使用原生指针的构造函数是explicit的,意味着不能进行隐式构造,只能显式构造

  1.  
    //错误!不能隐式调用构造函数!
  2.  
    TSharedPtr< float, Mode > FloatPtr = new float( 123.0f );

3、使用别的TSharedPtr拷贝构造。

  1.  
    TSharedPtr< bool, Mode > FirstBoolRef( new bool( false ) );
  2.  
    TSharedPtr< bool, Mode > SecondBoolRef( FirstBoolRef );
  3.  
    TSharedPtr< bool, Mode > ThiredBoolRef = FirstBoolRef;//效果同上

4、使用别的TSharedRef构造。

  1.  
    TSharedRef< int32, Mode > MySharedRef( new int32( 1 ) );
  2.  
    TSharedPtr< int32, Mode > MySharedPtr( MySharedRef );
  3.  
     

能够这样做的原因在于TSharedPtr提供了以TSharedRef为参数的构造函数,源码如下

  1.  
    FORCEINLINE TSharedPtr( TSharedRef< OtherType, Mode > const& InSharedRef )
  2.  
    : Object( InSharedRef.Object )
  3.  
    , SharedReferenceCount( InSharedRef.SharedReferenceCount )
  4.  
    {
  5.  
    // There is no rvalue overload of this constructor, because 'stealing' the pointer from a
  6.  
    // TSharedRef would leave it as null, which would invalidate its invariant.
  7.  
    }

5、通过TWeakPtr构造

  1.  
    //这里WeakInt是一个TWeakPtr< int32, Mode >
  2.  
    TSharedPtr< int32, Mode > SharedInt( WeakInt.Pin() );

 这个方法的原理在于TWeakPtr::Pin返回了一个TSharedPtr,然后用这个TSharedPtr去进行拷贝构造。

6、使用MakeSharable构造。

TSharedPtr< float, Mode > FloatPtr = MakeShareable( new float( 30.0f ) );

MakeShareable源码如下

  1.  
    template< class ObjectType >
  2.  
    FORCEINLINE SharedPointerInternals::FRawPtrProxy< ObjectType > MakeShareable( ObjectType* InObject );

我们可以发现,MakeShareable其实是构造了一个SharedPointerInternals::FRawPtrProxy< ObjectType >,而TSharedPtr提供了一个以SharedPointerInternals::FRawPtrProxy< ObjectType >为参数的构造函数,如下

  1.  
    FORCEINLINE TSharedPtr( SharedPointerInternals::FRawPtrProxy< OtherType > const& InRawPtrProxy )
  2.  
    : Object( InRawPtrProxy.Object )
  3.  
    , SharedReferenceCount( InRawPtrProxy.ReferenceController )
  4.  
    {
  5.  
    ...
  6.  
    }

这个构造函数支持隐式转换,所以

TSharedPtr< float, Mode > FloatPtr = MakeShareable( new float( 30.0f ) );

这行代码的本质是先构造一个临时变量,然后再用临时变量构造TSharedPtr。

7、使用MakeShared构造。

TSharedPtr< float, Mode > FloatPtr = MakeShared(30.f);

注意,MakeShared的参数是目标类型构造函数的参数。MakeShared源码如下

  1.  
    template <typename InObjectType, ESPMode InMode = ESPMode::Fast, typename... InArgTypes>
  2.  
    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:我们先把它们的参数和返回值用伪代码列一下,

  1.  
    template< class T>
  2.  
    SharedPointerInternals::FRawPtrProxy<T> MakeShareable( T* ptr)
  3.  
     
  4.  
    template <typename T, ESPMode InMode = ESPMode::Fast, typename... InArgTypes>
  5.  
    TSharedRef<T, InMode> MakeShared(InArgTypes&&... Args)

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

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

使用时,它们的形式如下

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

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

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhfhghhk
系列文章
更多 icon
同类精品
更多 icon
继续加载