How should std::map be used with a value that does not have a default constructor?

前端 未结 3 1695
闹比i
闹比i 2021-01-18 16:58

I\'ve got a value type that I want put into a map. It has a nice default copy constructor, but does not have a default constructor.

I believe that so long as I stay

相关标签:
3条回答
  • 2021-01-18 17:33

    You can simply "insert-or-overwrite" with the standard insert function:

    auto p = mymap.insert(std::make_pair(key, new_value));
    
    if (!p.second) p.first->second = new_value;  // overwrite value if key already exists
    

    If you want to pass the elements by rerference, make the pair explicit:

    insert(std::pair<K&, V&>(key, value));
    

    If you have a typedef for the map like map_t, you can say std::pair<map_t::key_type &, map_t::mapped_type &>, or any suitable variation on this theme.


    Maybe this is best wrapped up into a helper:

    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; }
    }
    
    0 讨论(0)
  • 2021-01-18 17:45

    You could first get the position to insert the pair with lower_bound, then check if it's already there, and if not, insert it, providing the iterator where to insert. Something along those lines.

    0 讨论(0)
  • 2021-01-18 17:45

    There are two things you missed in the interface of map (and the like):

    • insert(value_type) returns a std::pair<iterator, bool>, the .first member points to the element with the key you tried to insert and the .second member indicates whether it is actually the element you tried to insert or another that previously was in the container.
    • insert(iterator, value_type) allows you to give a hint as to where insert

    The latter is not necessarily useful in your situation though.

    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);
    }
    

    If you type does not support assignment and there is no swap, however, you need to bite the bullet:

    // 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
    

    In C++11, the insert methods are doubled:

    • insert(value_type const&) // insertion by copy
    • insert(P&&) // insertion by move

    and with perfect forwarding we get the new emplace method. Similar to insert, but which construct the element in place by forwarding the arguments to its constructor. How it differentiate arguments for the key and value is a mystery to me though.

    0 讨论(0)
提交回复
热议问题