调用带有 unique_ptr 对象的函数

calling functions which take unique_ptr object

我有一个函数,其中回调接收一个 event 持有 data 的 unique_ptr 实例。我可以通过 event.data.get() 检索 char* ,这应该给我指针但不是所有权允许对象自由删除它。现在我有另一个函数,它采用 otherdata 的 unique_ptr 实例,当然管理所有权,因此该函数可以自由释放它。 所以我试图从回调中获取 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 和移动语义非常混乱。

stream.write() 可能需要一个 const char *,如果是这样,您将不需要 std::move() 将数据传递给它。当您需要更改 unique_ptr 的数据所有权时,使用 std::move()。但在这种情况下,数据归 event 所有,我们只是暂时让 stream.write() 访问它。

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

如果 stream.write() 需要 std::unique_ptr,那么您需要 std::move() 来自 event.data 的数据到此函数。此移动后,event.data 处于 "moved from" 状态,无法再访问数据。

void cbdata(DataEvent& event){
    stream.write(std::move(event.data), event.length);
    // now 'event.data' owns nothing and holds a null pointer
}

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

此外,您的 cbdata 通过 const& 接收事件。这是一个 "borrow & do not change" 语义。因此,它不应提供 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'!
    }
    

    当然在Eventclass的其余部分,必须支持data为nullptr的情况

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

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

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

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