调用带有unique_ptr对象

时间:2019-09-07 11:22:07

标签: c++ unique-ptr ownership-semantics

我有一个函数,其中回调函数接收一个event并拥有一个unique_ptr实例的data。我可以通过char*检索event.data.get(),这应该给我指针,但没有所有权,允许对象自由删除它。现在,我有了另一个函数,该函数采用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和move语义非常混乱。

2 个答案:

答案 0 :(得分:2)

您的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);
    }
    

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

答案 1 :(得分:1)

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处于“已移出”状态,并且无法再访问数据。

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