c++ 在指向同一资源的两个智能指针之间切换所有权(是否需要新类型?)

aemubtdh  于 2023-01-22  发布在  其他
关注(0)|答案(1)|浏览(143)

我需要一个智能指针,删除底层资源,每当它运行的范围(如unique_ptr),但可以复制流形。它应该是从std::weak_ptr构造,以提高临时所有权,并在它运行的情况下,它将删除资源在任何情况下,并使其他ptrs无效(例如,通过控制块)。
让我用一个非编译的例子来解释:在下面的代码中,我尝试通过一个自定义智能指针来建立一个特定于操作系统的线程实现的所有权:twin_ptr只有当没有其他的twin_ptr拥有相同的资源时,这个指针才拥有这个资源。复制一个孪生指针会让原来的指针"拥有"这个资源,而复制的孪生指针将是std::weak_ptr,它将只引用对象,但可以离开作用域而不删除它。通过这种方式,我现在可以建立线程,1)拥有自己或2)由另一个线程拥有,并在任何阶段在这两种形式之间切换。

    • 注意**:我没有twin_ptr的实现!这个概念只是有一个智能指针,在所有权是released()的情况下,将所有权传递给他的 * 兄弟 *。

我的意思是:

#include <future>
#include <thread>
#include <memory_resource>
#include <memory>
#include <cstdio>

using allocator_t = std::pmr::polymorphic_allocator<std::byte>;

template <typename T>
class twin_ptr;

struct task
{
    task() = default;

    task(int config, std::packaged_task<void()> fn, twin_ptr<task>* handle)
        :   fn_{ std::move(fn)}
    {
        // Will invoke "worker" in another thread
        // "handle" param will be passed to thread func as void* const
        task_creation_foo_specific_to_my_os(&worker, handle);
    }

    static auto worker(void* const arg) -> void {
        {
            // Copies the twin_ptr into to task scope, copied instance will not be owning by default
            twin_ptr<task> handle = *static_cast<twin_ptr<task>*>(arg);
            handle->fn_();
        }
        // End of scope will delete the task object in case our twin_ptr is still
        // owning it.
    }

    std::packaged_task<void()> fn_;
};

auto create_task(int config, std::packaged_task<void()> fn, allocator_t allocator = {})
{
    auto ptr = twin_ptr<task>{};
    
    ptr = allocate_twin<task>(allocator, config, std::move(fn), &ptr);

    return ptr;
}

int main()
{
    twin_ptr<task> ptr = create_task();

    // Will release ownership and carry it to the thread-internal copy of the twin_ptr
    // (thus lifetime management will be done by the task from now on)
    ptr.release(); 

    printf("-- end--\n");
}

因为缺少twin_ptr实现,所以无法编译代码,但我希望它是清晰的,否则请询问

    • 注意**:为了简洁起见,故意省略了同步原语。显然,线程中twin_ptr的复制应该在create_task()中的赋值运算符完成之后进行。

问题:

是否已经可以用默认的标准库函数来编写这个功能部件,或者您是否看到了用另一种优雅的方式来实现相同功能的方法?

owfi6suc

owfi6suc1#

是否已经可以使用默认标准库函数编写此功能部件。
是的,你有一个std::shared_ptr,然后分发指向同一个对象的std::weak_ptr

class task : public std::enable_shared_from_this<task>
{
    task() = default;

    task(int config, std::packaged_task<void()> fn)
        :   fn_{ std::move(fn)}
    {
    }

    void start()
    {
        // Will invoke "worker" in another thread
        // synchronisation needed to ensure handle is assigned in worker before constructor returns
        task_creation_foo_specific_to_my_os(&worker, this);
    }

    static auto worker(void* const arg) -> void {
        auto handle = *static_cast<task*>(arg)->weak_from_this();
        // ...
        if (auto ptr = handle->lock()) ptr->fn_();
        // ...
    }

    std::packaged_task<void()> fn_;

public:
    static std::shared_ptr<task> create_task(int config, std::packaged_task<void()> fn, allocator_t allocator = {})
    {
        auto ptr = std::allocate_shared<task>(allocator, config, fn);
        ptr->start();
        return ptr;
    }
};

如果您想格外小心,可以使用一个具有std::shared_ptr成员的不可复制对象,而不必注意永远不复制std::shared_ptr

相关问题