我有一个我想要放入地图的值类型。 它有一个很好的默认复制构造函数,但没有默认的构造函数。
我相信只要我不使用operator[]
,一切都会好的。
然而,我最终得到了像这样的非常丑陋的结构来实际插入一个对象。 (如果已经存在该键的值,我认为插入失败。)
// equivalent to m[5]=x but without default construction
std::map<int,X>::iterator it = m.find(5);
if( it != m.end() )
{
m->second = x;
}
else
{
m->insert( std::make_pair(5,x) );
}
我相信它会扫描地图两次,看起来也很难看。
有更简洁/更有效的方法吗?
答案 0 :(得分:2)
您可以首先获得与lower_bound
插入对的位置,然后检查它是否已经存在,如果没有,请插入它,提供迭代器插入位置。这些方面的东西。
答案 1 :(得分:2)
您可以使用标准insert
函数简单地“插入或覆盖”:
auto p = mymap.insert(std::make_pair(key, new_value));
if (!p.second) p.first->second = new_value; // overwrite value if key already exists
如果要通过重新引用传递元素,请明确显示该对:
insert(std::pair<K&, V&>(key, value));
如果您有map_t
等地图的typedef,则可以说std::pair<map_t::key_type &, map_t::mapped_type &>
或此主题的任何合适变体。
也许这最好包含在帮手中:
template <typename Map>
void insert_forcefully(Map & m,
typename Map::key_type const & key,
typename Map::mapped_type const & value)
{
std::pair<typename Map::iterator, bool> p = m.insert(std::pair<typename Map::key_type const &, typename Map::mapped_type const &>(key, value));
if (!p.second) { p.first->second = value; }
}
答案 2 :(得分:2)
map
(等等)的界面中有两件事你错过了:
insert(value_type)
返回std::pair<iterator, bool>
,.first
成员指向包含您尝试插入的键的元素,.second
成员指示它是否实际上是您的元素试图插入或以前在容器中的另一个。insert(iterator, value_type)
允许您提示插入后者在你的情况下并不一定有用。
typedef std::map<int,X> Map;
// insert and check
std::pair<Map::iterator, bool> const result =
map.insert(std::make_pair(5, x)); // O(log N)
if (not result.second)
{
result->first.second = x; // O(1)
// OR
using std::swap;
swap(result->first.second, x);
}
如果你输入的类型不支持赋值,但没有交换,你需要咬紧牙关:
// locate and insert
Map::iterator position = map.lower_bound(5); // O(log N)
if (position != map.end() and position->first == 5)
{
position = map.erase(position); // O(1)
}
map.insert(position, std::make_pair(5, x)); // O(log N) if rebalancing
在C ++ 11中,insert
方法加倍:
insert(value_type const&)
//按副本插入insert(P&&)
//通过移动并且通过完美转发,我们获得了新的emplace
方法。与insert类似,但通过将参数转发给其构造函数来构造元素。它如何区分关键和价值的论点对我来说是一个谜。