有没有一种意识形态上的方法来避免这种Naked New的使用?

问题描述 投票:0回答:1

在我的应用程序中,我需要设置回调,其唯一的职责是在一个单独的对象中更新与已完成事件相关联的状态,以便以后可以查询它。然而,由于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<render_future::shared_state>(future.state)在我看来,这似乎是某种反常的做法:用赤裸裸的 newdelete 与智能指针相结合。

但问题是,由于回调必须是函数指针,所以我的lambda表达式不能复制或引用其他对象,唯一的办法是通过回调来获取 shared_state 对象里面的lambda要把它的指针传进去;同样,因为我不能保证它的寿命没有过期,所以我需要把它以指针的形式传给一个 weak_ptr 以便在对象仍然存在的情况下(而且只有在)可以对其进行操作。

所以最终,我的问题是:是否有一种表意的方式来通过 shared_state 到这个回调中,其中

  1. 我可以检查是否该对象仍然存在,而
  2. 也消除了我对裸体的使用 newdelete 调用?
c++ opencl c++20
1个回答
3
投票

在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<>::release().

auto ptr = std::make_unique<std::weak_ptr<render_future::shared_state>>(future.state);

event.setCallback(CL_COMPLETE, callback, ptr.release());

但是由于你调用的是一个无捕获lambda的C函数,所以这里并没有意外的异常情况需要保护,所以这是否比你现在的做法有真正的改进值得商榷。


0
投票

你可以在map里面存储一个智能指针,以一个非所有者的指针作为键。回调可以将指针从地图中清除,从而释放所有权。地图必须比回调的时间长。如果需要的话,你可以求助于静态存储。

在拥有唯一所有权的情况下,你反而可以直接将对象本身存储在map中。

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

© www.soinside.com 2019 - 2024. All rights reserved.