在unordered_map中放置结构,引用问题

时间:2014-04-24 15:09:29

标签: c++ boost unordered-map

我对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并进行修改,但我认为这不是一种有效的方法。

2 个答案:

答案 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>的构造函数,该构造函数将复制stringCLIENT_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的成员不是可移动构造的,因此移动与副本相同。