Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/127.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 对于没有默认构造函数的值,应该如何使用std::map?_C++ - Fatal编程技术网

C++ 对于没有默认构造函数的值,应该如何使用std::map?

C++ 对于没有默认构造函数的值,应该如何使用std::map?,c++,C++,我有一个值类型,我想把它放到地图上。 它有一个很好的默认复制构造函数,但没有默认构造函数 我相信只要我不使用操作符[],一切都会好起来的 然而,我最终得到了非常丑陋的构造,像这样来插入一个对象。 (我认为,如果该键已有值,则insert将失败) //相当于m[5]=x,但没有默认构造 std::map::iterator it=m.find(5); 如果(it!=m.end()) { m->second=x; } 其他的 { m->insert(标准::生成一对(5,x)); } 我相信它会扫

我有一个值类型,我想把它放到地图上。 它有一个很好的默认复制构造函数,但没有默认构造函数

我相信只要我不使用
操作符[]
,一切都会好起来的

然而,我最终得到了非常丑陋的构造,像这样来插入一个对象。 (我认为,如果该键已有值,则insert将失败)

//相当于m[5]=x,但没有默认构造
std::map::iterator it=m.find(5);
如果(it!=m.end())
{
m->second=x;
}
其他的
{
m->insert(标准::生成一对(5,x));
}
我相信它会扫描地图两次,而且看起来很难看


是否有一种更简洁/更有效的方法来执行此操作?

您可以首先获得插入具有
下限的对的位置,然后检查它是否已经存在,如果不存在,则插入它,提供插入的迭代器。您可以使用标准的插入功能简单地“插入或覆盖”:

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
的界面中,有两件事您遗漏了(等等):

  • insert(value\u type)
    返回一个
    std::pair
    ,第一个
    成员用您尝试插入的键指向元素,
    。第二个
    成员指示它实际上是您尝试插入的元素还是之前在容器中的另一个元素
  • insert(迭代器,值类型)
    允许您给出插入位置的提示
不过,后者在您的情况下并不一定有用

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);
}
在C++11中,
insert
方法加倍:

  • insert(value\u type const&)
    //复制插入
  • insert(P&&)
    //移动插入

通过完美的转发,我们得到了新的
emplace
方法。类似于insert,但它通过将参数转发给其构造函数来就地构造元素。然而,它如何区分键和值的参数对我来说是个谜。

这里的现有答案@miaout17,是的,现有答案将解决它。然而,在我看来,它所解决的问题是另一个问题。@miaout17,实际上这并不能完全解决它。在这种情况下,如果已经存在新值,则不将其存储到映射中。但是不要用一个新的值重写它。要做到这一点,函数需要稍微调整。。。有人发布了一个正确的解决方案,然后删除了他们的答案:(我唯一的问题是从
key
new\u value
构造一对可能很昂贵,或者在C++11的情况下不可能(
new\u value
只能移动)。我在代码中遇到了这个问题:(@GMan:when不使用一对引用?实际上,
make_-u-pair
推导引用类型吗?否则使用
std::tie
。这两种方法都不起作用,因为
insert
需要一个
pair-u-type
。这真的只是容器的一个缩影。@GMan:Yes,true,
tie
生成元组,而不是
pair
.Meh,您可以将这对引用显式化;我添加了这一点。由于
insert()
本身引用了
map::value\u 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; }
}
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