【问题标题】:Is there an ideomatic way to avoid this use of Naked New?有没有一种理想的方式来避免这种裸新的使用?
【发布时间】:2020-05-07 02:27:51
【问题描述】:

在我的应用程序中,我需要设置回调,其唯一职责是在单独的对象中更新与已完成事件关联的状态,以便以后可以对其进行查询。但是,由于 API 的设计方式,我不能保证在事件完成时其他对象仍然拥有,因此我需要存储指向该对象的指针,并且因为回调 API 是基于 C 的,我最终存储了一个指向智能指针的原始指针,这是我见过的最丑陋的代码*。

* 反正最近几个小时...

这就是我写来完成这个的:

event.setCallback(CL_COMPLETE, [](cl_event event, cl_int, void* ptr) {
    auto ptr_ptr = static_cast<std::weak_ptr<render_future::shared_state>*>(ptr);
    if(auto shared_ptr = ptr_ptr->lock()) {
        auto & shared_state = *shared_ptr;
        std::lock_guard lock{ shared_state.mutex };
        shared_state.event_state[event] = true;
    }
    delete ptr_ptr;
}, new std::weak_ptr<render_future::shared_state>(future.state));

我特别反对我自己使用new std::weak_ptr&lt;render_future::shared_state&gt;(future.state),在我看来这似乎是某种反模式:将裸newdelete 与智能指针结合使用。

然而,问题在于,因为回调必须是函数指针,我的 lambda 表达式无法复制或引用其他对象,而在 lambda 中获取 shared_state 对象的唯一方法是将其指针传入;再一次,因为我不能保证它的生命周期没有过期,我需要以指向 weak_ptr 的指针的形式获取它,以便在(且仅当)对象仍然存在时可以对其进行操作。

所以最终,我的问题是:有没有一种理想的方式将shared_state 传递到这个回调中

  1. 我可以检查以确保对象仍然存在,而
  2. 还消除了我对裸newdelete 调用的使用?

【问题讨论】:

    标签: c++ opencl c++20


    【解决方案1】:

    在 lambda 中,只需使用 unique_ptr 即可实现明显的改进:

    auto callback = [](cl_event event, cl_int, void* ptr) {
        std::unique_ptr<std::weak_ptr<render_future::shared_state>> ptr_ptr{ static_cast<std::weak_ptr<render_future::shared_state>*>(ptr)};
        if(auto shared_ptr = ptr_ptr->lock()) {
            std::lock_guard lock{ shared_state->mutex };
            shared_state->event_state[event] = true;
        }
    }
    

    在事物的创造方面,您可以使用std::unique_ptr&lt;&gt;::release()

    auto ptr = std::make_unique<std::weak_ptr<render_future::shared_state>>(future.state);
    
    event.setCallback(CL_COMPLETE, callback, ptr.release());
    

    但由于您使用无捕获的 lambda 调用 C 函数,因此这里并没有需要保护的意外异常,因此与您当前所做的相比,这是否是一个真正的改进是值得商榷的。

    【讨论】:

    • 我最终选择了第一个建议,而不是第二个。就我而言,ptr.release() 的危险性只比赤裸裸的new 稍微低一点,所以至少通过删除delete,我觉得代码得到了改进。
    【解决方案2】:

    您可以在映射中存储指向对象的智能指针,并将非拥有指针作为键。回调可以从映射中删除指针,从而释放所有权。地图必须比回调更有效。如果需要,您可以使用静态存储。

    使用唯一所有权,您可以直接将对象本身存储在地图中。

    在唯一所有权的情况下,数据结构跟踪分配的额外复杂性和开销是否值得摆脱显式的 new 和 delete 是值得商榷的。有了共享所有权,这可能是一个更好的选择。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-09-23
      • 2014-02-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-14
      • 1970-01-01
      • 2022-11-16
      相关资源
      最近更新 更多