我对boost unordered_map有以下定义
typedef boost::unordered::unordered_map<std::String, CLIENT_STATE> CLIENT_MAP;
CLIENT_STATE是一个定义如下的结构:
typedef struct{
unsigned char state;
/* socket fd of the client */
int fd;
/* File path requested by the client */
char file_path [255];
/* Current file offset */
unsigned long int offset;
} CLIENT_STATE;
当我尝试使用emplace向CLIENT_MAP添加元素时,CLIENT_MAP会创建元素的单独副本,与原始定义无关。即对原始元素定义的任何修改,都不会对unordered_map中的元素进行任何更改。
之前我被告知,使用emplace不会克隆我的原始元素,它会将它直接放在容器中检查link
那么让容器中添加元素的更改影响原始定义的最佳方法是什么,反之亦然。
这就是我的意思:
CLIENT_STATE new_client;
new_client.offset = 5;
client_map.emplace("Test", new_client);
new_client.offset = 10;
cout << client_map["Test"].offest;
cout不会打印10,它会打印5。
目前要解决这个问题,在unordered_map的一个元素之后,我处理返回的std :: pair并进行修改,但我认为这不是一种有效的方法。
答案 0 :(得分:2)
emplace
,允许从传递给它的参数构造一个对象,而不需要先创建要传递的对象,通过删除通常由于创建对象而发生的复制结构来节省开销插入。
你可以通过使用指针实现你想要的东西
typedef boost::unordered::unordered_map<std::String, CLIENT_STATE* > CLIENT_MAP;
但是使用指针可能会对内存处理产生问题,例如对象删除等。
您可以考虑使用boost::shared_ptr
,如下所示:
(我没有shared_ptr / boost专家)
include <boost/shared_ptr.hpp>
boost::unordered::unordered_map<std::String,
boost::shared_ptr<CLIENT_STATE> > client_map ;
std::string s ="client1" ;
CLIENT_STATE *c1 = new CLIENT_STATE;
//c1->state, c1->id, etc
my_map[t] = c1 ;
如果您不需要复制地图中存储的对象,可以使用C ++ 11 std::unique_ptr
答案 1 :(得分:1)
您不想使用emplace
。你想要的是共享指针语义。但是,对于此问题的未来访问者,解释如何正确使用emplace
与关联容器可能会有用。
正如@ gha.st正确评论的那样,emplace
将调用std::pair<std::string, CLIENT_STATE>
的构造函数,该构造函数将复制string
和CLIENT_STATE
个对象。
从C ++ 11开始,std::pair
有一个额外的构造函数重载,它采用标记类型std::piecewise_construct_t
的第一个参数,它允许std::pair
自身的成员进行安装。观察:
client_map.emplace(std::piecewise_construct,
std::forward_as_tuple("Test"),
std::forward_as_tuple(5));
现在emplace
将调用pair
的tag-overloaded构造函数,而后者将从转发的元组中的参数中构建其两个数据成员。
在这种情况下,CLIENT_STATE
是一种聚合类型,因此没有我们可以使用int
这样调用的构造函数。但以上是与典型的C ++类类型一起使用的一般技术。我们可以为聚合做的最好的事情是从临时构建它:
client_map.emplace("Test", CLIENT_STATE{ 0, 0, "", 5 });
在这种情况下,这没有任何帮助,因为CLIENT_STATE
的成员不是可移动构造的,因此移动与副本相同。