S. K. S. K. - 1 month ago 10
C++ Question

Why std::pair<const int, int> does not work with some STL containers?

It seems that some containers accept

std::pair<const int, int>
as a value type, but some do not. The problem is of course in the
const
part.

I did some googling and found that only
std::vector
requires copy-assignable data. However,
std::pair<const int, int>
works just fine with
std::vector
,
std::set
and
std::list
(and perhaps other containers), but not with
std::map
and
std::priority_queue
(the latter really bugs me).

The following compiles without problems (gcc 6.1.0)

std::vector<std::pair<const int, int>> vector;
vector.push_back(std::make_pair(3, 5));
std::set<std::pair<const int, int>> set;
set.insert(std::make_pair(3, 5));
std::list<std::pair<const int, int>> list;
list.push_back(std::make_pair(3, 5));


But this results in compilation errors:

std::priority_queue<std::pair<const int, int>> pq;
pq.push(std::make_pair(3, 5));
std::map<int, std::pair<const int, int>> map;
map[2] = std::make_pair(3, 5);



error: assignment of read-only member ‘std::pair<const int, int>::first’



What is the reason behind this? Shouldn't
std::map
and
std::set
have the same behavior given that they have the same underlying implementation? Why does it work with
std::vector
although it requires to move data?

Answer

Anything that requires assignment will break.

  • vector::push_back doesn't require assignment, only copy/move construction.
  • ditto for set::insert.
  • ditto for list::push_back.
  • priority_queue::push needs to move around the existing elements to maintain the heap property (via std::push_heap), which requires assignment.
  • map[2] = stuff; is literally an assignment. Use map::insert or map::emplace if you want it to work.
Comments