【问题标题】:How to use smart pointers with setUserData(void*)?如何在 setUserData(void*) 中使用智能指针?
【发布时间】:2016-06-30 15:00:43
【问题描述】:

是否可以将 c++11 智能指针与节点用户数据一起使用?有人试过吗?

node->setUserData(void* usrData);
node->getUserData();

已解决:

我想出了一种在节点中存储对象而不必手动删除主题的方法(当节点被销毁时会自动删除),它可能不是最好的解决方案,但它仍然是一个解决方案,它涉及从 cocos2d::Ref 类和使用节点 setUserObject(Ref* ptr)!

这就是我实现它的方式:

1)- 创建一个继承自 cocos2d::Ref 类的类/结构。

2)- 用您的自定义属性和方法填充它。

3)- 确保对象调用 autorelease()。

struct Box : public cocos2d::Ref
{
    // some properties here

    Box() {
        //autorelease means let other Nodes retain and release this object.
        //if you don't call autorelease then the object destructor won't get called which means in turn object memory is not released.
        this->autorelease();
    }

    ~Box() {
        //just to check if the object destructor is called or not.
        log("=========================");
        log("Box is destroyed"); 
        log("=========================");
    }

};

4)- 创建一个对象实例并将其指针放在任何 Node UserObject 中,如下所示:

auto box = new Box;
this->setUserObject(box);// am putting it in the Layer UserObject

现在只要层/节点被销毁,盒子对象就会自动销毁(不需要删除)

PS:您应该正确退出 cocos2d-x 应用程序,以便调用节点(节点,层,场景)析构函数,以便正确销毁节点子节点(调用子析构函数)...只需按回按钮,如果您在模拟器中或使用调用 Director::end() 的关闭按钮。

【问题讨论】:

  • 如果函数没有声明为采用智能指针,那么不是真的。您可以使用智能指针,然后将实际指针传递给函数,但是如果智能指针决定删除包含指针,它确实违背了使用智能指针开始的全部要点(双关语不是有意的)。
  • 所以即使我将 shared_ptr::get() 方法与 setUserData ...即使一个节点用户数据持有它?
  • 如果你使用例如some_share_ptr.get() 获取原始指针,共享指针如何能够跟踪原始指针?它只是不能,所以当所有共享指针超出范围时,指针将被删除,留下一个流浪指针。
  • 但是如果我使用 setUserData(&some_share_ptr) 会被删除吗?
  • 这并不比使用来自共享指针对象的原始指针更好。使用指向共享指针对象的指针不会修改共享指针对象引用计数器,它用于跟踪共享指针对象。

标签: c++ c++11 cocos2d-x cocos2d-x-3.0


【解决方案1】:

这是一条评论,但太长了。

我不会像 @Joachim Pileborg 在 cmets 中那样认为它毫无希望(尽管他的观点原则上是正确的)。您唯一需要假设的是 setUserData 只是在观察,即它不执行与内存相关的操作,尤其是不执行 delete

然后您可以简单地在“外部”使用智能指针,

auto ptr = std::make_unique<some_object>();
node->setUserData(ptr.get());

现在,如果程序随后以正确的方式退出,至少您不必手动删除ptr。但是,正如 Joachim 所提到的,您当然必须确保 ptr 的存在时间只要它可以在 node 中使用。

或者,您可以围绕 node 类编写小型包装器,该类包含一个 shared_ptr&lt;void&gt; ptr 变量并提供一个 setUserData(shared_ptr&lt;void&gt;) 方法。如果调用此方法,它首先复制共享指针并在内部调用node-&gt;setUserData(ptr.get()) 方法。然后保证底层对象保持活动状态。

【讨论】:

  • 但是如果指针在 ptr 离开作用域的那一刻被释放,那么将指针存储在用户数据中的意义何在?
  • @Joseph:重点(在第一个替代方案中)是确保智能指针只要您使用它就不会离开范围。但是,如果它应该通过某种异常,它仍然会正确执行delete-ing 的任务。如果您怀疑是否可以使指针保持活动状态,请使用第二种选择:将所有内容包装在一个存储智能指针的类中(并由此确保它是活动的)。这与您的解决方案方法非常相似,但可能更通用(一个 CRTP 类就足够了,而不必为每个类重新应用您的解决方案)。
  • 由于 cocos2d 是开源的,我发现其他解决方案之一是重载 setuserdata()(因为它是虚拟的)并使其接受 @davidhigh 建议的智能指针。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-08-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-18
  • 2019-09-21
  • 2019-11-17
相关资源
最近更新 更多