在智能指针的反引用值上调用std :: move()

时间:2019-05-24 17:20:40

标签: c++

class A{
public:
  void AddObject(MsgType msg){
    msg_queue.push_back(msg);
  }
private:
 std::queue<MsgType> msg_queue;
}

我有A类及其方法AddObject()。本课程有两种类型的客户。第一种类型是他们仅获得boost::sharedPtr<MsgType>而其他客户端拥有std::shared_ptr<MsgType>const MsgType&的地方。

AddObject()的签名应该是什么,以便避免在此进行转换或复制。如果我使用AddObject(MsgType msg),则必须从客户端致电:

boost::shared_ptr<MsgType> msg;
AddObject(std::move(*msg));

std::shared_ptr<MsgType> msg;
AddObject(std::move(*msg));

,我可以使用std::move()中的AddObject()将其存储在队列中。 考虑到性能,这里的API应该是什么?

MsgType的大小约为1.4 MB,这是protobuf消息。对于protobuf而言,移动构造函数非常昂贵。所以看起来我不能在这里使用std :: move。

1 个答案:

答案 0 :(得分:1)

您最初编写AddObject()的方式,并没有假设输入MsgType的所有权。它不知道或不在乎MsgType是如何分配的,或者谁应该拥有它。在这种情况下,您唯一可以做的就是为自己复制一个副本,这就是您当前所做的事情。

如果您希望AddObject()在不制作副本的情况下取得所有权,那么AddObject()需要明确说明其期望如何管理所有权。您可以通过以下两种方式之一表达所有权语义:

  • 使用std::unique_ptr(或boost::unique_ptr)要求排他所有权:

    class A{
    public:
      void AddObject(std::unique_ptr<MsgType> msg){
        msg_queue.push(std::move(*msg));
      }
    private:
      std::queue<MsgType> msg_queue;
    };
    

    或更佳:

    class A{
    public:
      void AddObject(std::unique_ptr<MsgType> msg){
        msg_queue.push(std::move(msg));
      }
    private:
      std::queue<std::unique_ptr<MsgType>> msg_queue;
    };
    
  • 使用std::shared_ptr(或boost::shared_ptr)共享所有权:

    class A{
    public:
      void AddObject(std::shared_ptr<MsgType> &msg){
        msg_queue.push(msg);
      }
    private:
      std::queue<std::shared_ptr<MsgType>> msg_queue;
    };
    

否则,您真正能做的就是std::move()输入MsgType内容,然后让调用者担心以后再释放MsgType

class A{
public:
  void AddObject(MsgType &msg){
    msg_queue.push(std::move(msg));
  }
private:
  std::queue<MsgType> msg_queue;
};

但是,在您的情况下,后一种选择可能不太可行,因为您声称移动protobuf对象非常昂贵。在这种情况下,您应该只在指向protobuf对象的指针周围移动,而不是在对象本身周围移动。这就是(std|boost)::unique_ptr(std|boost)::shared_ptr发挥作用的地方。

如果您要对类进行编码以同时支持stdboost智能指针,则必须为每种类型重载AddObject()或为其提供一个模板参数,您可以根据需要专门研究。