首页 > 解决方案 > 调用接受 unique_ptr 对象的函数

问题描述

我有一个函数,其中回调接收一个event持有 unique_ptr 实例的data. char*我可以通过它来检索event.data.get()应该给我指针而不是所有权,从而允许对象自由删除它。现在我有另一个函数,它接受一个 unique_ptr 实例,otherdata当然管理所有权,所以该函数可以自由地释放它。所以我试图data从回调中获取并将其传递给安全的函数otherdata

void cbdata(const DataEvent& event){
                char* datatobewritten = event.data.get();
                stream.write(std::move(datatobewritten),event.length));
            }

上面的示例似乎确实有效,但我不确定这是否是正确的方法。事件是否放弃所有权?如果是这样,放弃所有权是否安全?

为什么这会导致编译器错误:Call to implicitly-deleted copy constructor of 'std::unique_ptr<char []>'

void cbdata(const DataEvent& event){
                stream.write(event.data,event.length);
            }

如果 event.data 给我一个 unique_ptr 并且 stream.write 需要一个 unique_ptr 那么上面的代码不应该正常工作吗?或这个

stream.write(std::move(event.data), event.length);

抱歉,我的 C++ 知识非常有限,所以 unique_ptr 和 move 语义非常混乱。

标签: c++unique-ptrownership-semantics

解决方案


stream.write您想要拥有正在打印的事件片段的所有权,这有点不寻常。似乎它拥有事件的一部分,而调用者仍然是其余部分的所有者。在那次调用之后,一个event对象仍然是不完整的,因为它event.data被放弃了。

此外,您cbdata通过const&. 这是一种“借用且不改变”的语义。因此,它不应授予其所有权event或其任何部分。

一些选项:

  1. 将整个事件的所有权传递给了stream,而不仅仅是data。不过,您cbdata需要先获得所有权。

  2. 不要给stream. 通常流仅用于向用户呈现数据,而不是以任何方式操纵它们。

  3. 更改您的活动,以便它可以data永久发布。你需要这样的东西:

    std::unique_ptr<DataType> Event::releaseData() {
        return std::move(this->data);
        //after the call, this->data is 'nullptr'!
    }
    

    当然,在其余的课程中,必须支持 nullptrEvent的情况。data

    请注意,这会更改event对象,而不是const函数。您cbdata将不适用于const&事件对象。

  4. 您还可以将数据复制到流中。如果数据很大,可能效率低下,但如果DataType是可复制的,则完全可以。你可以这样做:

    void cbdata(const DataEvent& event){
        stream.write(std::make_unique<DataType>(*event.data),event.length);
    }
    

    与任何其他副本一样,您必须注意,当副本被销毁时,实际上只删除了复制的数据。不应删除原件和副本之间共享的任何内容。


推荐阅读