4
int main() { using kv = std::pair<const int ,int>; std::vector<kv> vec; kv a{1,1}; vec.insert(vec.begin(),a); } 

I tried to insert element into that vector, but the compiler gives this eerror:

cannot assign to non-static data member 'first' with const-qualified type 'const int' 

while push_back() will compile correctly.Why is that? And what's the correct way to insert element into such vector?

ADD: The reason why I use std::pair<const int, int> is that I want to implement something like std::map, and the key in the key-value pair should not be modified. But I'm not sure if std::pair<const int, int> is the correct approach to do this.

2
  • 3
    Vector elements need to be copy assignable. Commented Aug 11, 2018 at 17:38
  • Use boost::flat_map<int,int> it already does what you likely want to implement. Commented Aug 11, 2018 at 17:39

2 Answers 2

9

Let's start by observing the following:

std::pair<const int, int> a, b; a=b; 

This will not compile either. Why? Because you are in effect declaring the following class:

class my_pair { public: // ... Bunch of irrelevant stuff const int first; int second; }; 

This class has its default assignment operator deleted. The default assignment operator is equivalent to assigning class members individually:

pair<first,second> &operator=(const pair<first, second> &other) { first=other.first; second=other.second; return *this; } 

This is a rough example of what a default assignment operator looks like.

But you can't modify the first class member, here, because it is a const class member. Hence, the default assignment operator is deleted. End result: cannot assign a std::pair with a const value to another such pair.

You should now be able to figure out by yourself why insert() on your vector of pairs doesn't work.

insert() is, roughly, equivalent to shifting over all existing values by one, in the vector, after the insertion point, to make room for the new value. In other words:

 value[n+1]=values[n]; 

For all values past the insertion point (I'm ignoring for the moment the work done to grow the vector by one value, which is irrelevant to this discussion).

But the default assignment operator, as I explained, is deleted because the value has a const class member.

push_back works because nothing needs to be inserted, only a new value needs to be added to the end of the vector. If the vector needs to be reallocated, to accomodate its growth, that uses copy or move constructors, which are still valid for a std::pair with a const value.

Sign up to request clarification or add additional context in comments.

2 Comments

Nice explanation! And if I do want a container that contain some const pair, how should I do ? I think one way to do this is using a temp vector, poping out element to that temp vector, and push_back the element I want to insert, then push them back. But this solution looks stupid, any alternative?
You can use a list or, perhaps, a set.
3

Due to the const nature of the your data type kv (it has a const member first), it's copy-assignment operator has been implicitly deleted by the compiler.

Specifically, the overload of std::vector::insert you're using requires the data type (kv) be CopyAssignable (can be copied with a form of a = b). Your const member prohibits that.

On the other hand, std::vector::push_back requires the type be CopyInsertable (it can be copy-constructed), which your type is compliant with.

Therefore, insert will not work, but push_back will. The easiest fix is to lose the const from the kv first member. If you don't want someone to modify a key/value, then don't let them. When returning key/value tuples do so as const pointers or references.

1 Comment

Sound like a reasonable solution for this. But sometime it's natural that we want to modify the value after we get that kv pair reference, any potential solution to this?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.