【问题标题】:Copy a std::vector to boost::unordered_map<string, std::vector<foo>>将 std::vector 复制到 boost::unordered_map<string, std::vector<foo>>
【发布时间】:2014-01-11 07:11:46
【问题描述】:

将记录类型映射到字段值向量:

unordered_map<string, vector<string>> input_records;
string rec_type {"name"};
vector<string> fields { "field 1", "field 2", "field 3" };

我想将fields 复制到input_records[rec_type]。以下不起作用

_input_records[rec_type].insert(rec_deq.begin(), rec_deq.end()); 

然而 unordered_map 的 boost 文档包含以下内容:

template<typename InputIterator> 
void insert(InputIterator first, InputIterator last);

Inserts a range of elements into the container. Elements are inserted if and only if there is no element in the container with an equivalent key.

Throws:
When inserting a single element, if an exception is thrown by an operation other than a call to hasher the function has no effect.
Notes:
Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor.
Pointers and references to elements are never invalidated.

(写到这里,我意识到 InputIterator 可能指向一个键/值对序列,每个键/值对都将被插入到 Map 中。所以,错误的方法。)

如何最好地实例化和填充input_record[rec_type] 处的向量?一旦填充,向量将不会被修改。像input_record[rec_type] = fields这么简单吗?在这种情况下是否或可以应用“移动语义”?

【问题讨论】:

  • "像input_record[rec_type] = fields这么简单吗?"你试过了吗? ;-o 对于移动语义,将 fields 替换为临时的(在 C++11 中更容易)。 “放置”新值比移动它稍好一些,但考虑到您的数据类型,它不太可能很重要。

标签: boost c++11 vector unordered-map


【解决方案1】:

在标准关联容器中,你推入的是一个 std::pair,大多数时候使用 std::make_pair()。

#include <vector>
#include <string>
#include <unordered_map>
#include <iostream>

using namespace std;

int main()
{
    unordered_map<string, vector<string>> input_records;
    string rec_type {"name"};
    vector<string> fields { "field 1", "field 2", "field 3" };   

    input_records.insert( make_pair( rec_type, fields ) );

    for( const auto& text : input_records[rec_type] )
        cout << text << '\n';
}

Boost 容器也是如此,因为它们基于标准容器。

此外,由于 C++11 还有另一个函数 emplace(),它允许您“就地”创建一对,而不必先构建它然后将其传递给容器:

#include <vector>
#include <string>
#include <unordered_map>
#include <iostream>

using namespace std;

int main()
{
    unordered_map<string, vector<string>> input_records;
    string rec_type {"name"};
    vector<string> fields { "field 1", "field 2", "field 3" };   

    input_records.emplace( rec_type, fields );

    for( const auto& text : input_records[rec_type] )
        cout << text << '\n';
}

根据您传递数据的方式(右值引用?移动?等),会有更多或更少的副本。但是,适用于所有标准容器的简单经验法则是,您应该尝试使用 emplace(),直到您必须使用 insert()。

使用input_record[rec_type] 可以正常工作。但是,我建议使用 find() 代替,因为 [] 运算符将添加一个新元素,如果它没有找到,而 find() 将返回一个迭代器,它将是 container.end() 以防它找不到元素,因此,您只需将迭代器与 end() 进行比较即可知道是否找到了该元素。 这适用于所有标准关联容器和增强容器。

大多数时候,我使用封装在一个类中的关联容器来代表我想要的概念:比如 InputRecord 类。然后我提供了一个 find 函数(或任何适合域的操作名称),它完全符合我的要求,具体取决于具体情况:有时我希望它在找不到对象时抛出异常,有时我想创建一个新的记录我要找的那个不存在的时候,有时我想返回一个指针,有时我更喜欢返回一个 boost::optional。

您最好也这样做:将您的概念封装在一个类中,公开所需的服务,然后在该类中使用您想要的任何内容。如果以后需要,您甚至可以轻松切换到另一个容器,而无需更改接口,只需更改将操作容器的类中的代码。

【讨论】:

    猜你喜欢
    • 2018-07-24
    • 2011-09-17
    • 2017-02-01
    • 2016-01-24
    • 1970-01-01
    • 1970-01-01
    • 2012-01-06
    • 1970-01-01
    • 2011-05-19
    相关资源
    最近更新 更多