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。
答案 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
发挥作用的地方。
如果您要对类进行编码以同时支持std
和boost
智能指针,则必须为每种类型重载AddObject()
或为其提供一个模板参数,您可以根据需要专门研究。