题
我正在寻找一个懒惰创建的可共享指针.我有一个假设的大班Thing.事情很大,制作起来也很昂贵,但是虽然它们在代码中的任何地方都被使用(共享,传递,修改,存储供以后使用等),但实际上它们实际上并没有被使用,所以它们实际上是在拖延创建直到实际访问它们是可取的.因此,需要懒惰地创造,并且需要可分享.让我们调用这个封装指针包装器SharedThing.
class SharedThing { ... Thing* m_pThing; Thing* operator ->() { // ensure m_pThing is created ... // then return m_pThing ); } ... SharedThing pThing; ... // Myriads of obscure paths taking the pThing to all dark corners // of the program,some paths not even touching it ... if (condition) { pThing->doIt(); // last usage here }
要求
>实际事物的实例化必须尽可能延迟;只有在首次取消引用SharedThing时才会创建事物
> SharedThing必须安全使用,因此不需要工厂方法
> SharedThing必须具有shared_ptr(like)接口
>与尚未创建的SharedThing共享必须实际共享要创建的Thing,但Thing的实例化必须再次延迟,直到需要
>使用SharedThings必须尽可能简单(最好是100%透明,就像使用实际的东西一样)
>它必须有点高效
到目前为止,我们已经提出了四种选择:
选项1
typedef std::shared_ptr<Thing> SharedThing; SharedThing newThing() { return make_shared<Thing>(); } ... // SharedThing pThing; // pThing points to nullptr,though... SharedThing pThing(new Thing()); // much better SharedThing pThing = newThing(); // alternative
> 0%得分;从一开始就需要一个Thing实例
> 0%得分;你可以说SharedThing pThing;但这对事情有点过分担心
> 100%得分;)
> n.a.由于第1点
> 100%得分
> 0%得分,因为创造所有的东西到处(即使没有使用)是性能的消耗,这正是我问这个问题的原因:)
第1点和第6点缺乏得分是一个杀手;没有更多的选择1.
选项2
class SharedThing: public shared_ptr<Thing> {};
并覆盖特定成员以确保在取消引用shared_ptr时,它会及时创建Thing.
>也许可以通过覆盖正确的成员来实现(取决于stl的实现),但这很快变得混乱我认为
> 100%得分
> 100%得分,虽然模仿所有的构造函数和运算符是相当一些工作
>不知道这是否可以……
> 100%得分
如果内部事情巧妙地完成,则100%得分
这个选项优于1并且可能没问题,但看起来很混乱和/或黑客……
选项3.1
class SharedThing { std::shared_ptr<Thing> m_pThing; void EnsureThingPresent() { if (m_pThing == nullptr) m_pThing = std::make_shared<Thing>(); } public: SharedThing(): m_pThing(nullptr) {}; Thing* operator ->() { EnsureThingCreated(); return m_pThing.get(); } }
并为operator *和const版本添加额外的包装方法.
> 100%得分
> 100%得分
> do-able,但必须单独创建所有接口成员
> 0%得分;当附加到nullptr’ed SharedThing(例如operator =)时,它需要首先创建Thing以便能够共享
> 100%再次得分
> 50%得分; 2个间接
这一次在4上惨遭失败,所以这一次也是关闭的.
选项3.2
class SharedThing { typedef unique_ptr<Thing> UniqueThing; shared_ptr<UniqueThing> m_pThing; }
> 100%得分
> 100%得分
> do-able,但必须单独创建所有接口成员
> 100%得分
> 100%再次得分
> 25%得分?我们这里有3个间接……
除了建议的性能(但需要测试)之外,这似乎没问题.
选项4
class LazyCreatedThing { Thing* m_pThing; } typedef shared_ptr<LazyCreatedThing> SharedThing; SharedThing makeThing() { return make_shared<LazyCreatedThing>(); }
并添加各种运算符 – >重载使LazyCreatedThing看起来像一件事*
> 100%得分
>与上面的选项1相同的缺点
> 100%在这里毫不费力地得分
> 100%得分
> 0%得分;取消引用SharedThing会产生一个LazyCreatedThing,所以即使它可能有它的运算符 – >为了访问Thing,它永远不会被链接,导致(* pThing) – > doIt();
> 25-50%得分?我们这里有3个间接,如果我们可以使用std :: make_shared则有2个
在这里惨败5使这成为禁忌.
结论
到目前为止,最好的选择似乎是3.2;让我们看看我们还能想出什么!