调用接受对象的函数unique_ptr

calling functions which take unique_ptr object

本文关键字:unique ptr 函数 对象 调用      更新时间:2023-10-16

我有一个函数,其中回调接收一个event,其中包含data的unique_ptr instace。我可以通过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想要拥有它正在打印的事件片段的所有权,这有点不寻常。它似乎拥有事件的一部分,而调用方仍然是其余部分的所有者。在该调用之后,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'!
    }
    

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

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

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

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

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

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,所以你需要将数据从event.datastd::move()到这个函数。此移动后,event.data处于"移动自"状态,无法再访问数据。

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