3

How to push_back() to a C++ std::vector without using operator=() for which the default definition violates having const members?

struct Item {
  Item(int value)
    : _value(value) {
  }
  const char _value;
}

vector<Item> items;

items.push_back(Item(3));

I'd like to keep the _value const since it should not change after the object is constructed, so the question is how do I initialize my vector with elements without invoking operator=()?

Here is the basic error the g++ v3.4.6 is giving me:

.../3.4.6/bits/vector.tcc: In member function `Item& Item::operator=(const Item&)':
.../3.4.6/bits/vector.tcc:238:   instantiated from `void std::vector<_Tp, _Alloc>::_M_insert_aux(__gnu_cxx::__normal_iterator<typename _Alloc::pointer, std::vector<_Tp, _Alloc> >, const _Tp&) [with _Tp = Item, _Alloc = std::allocator<Item>]'
.../3.4.6/bits/stl_vector.h:564:   instantiated from `void std::vector<_Tp, _Alloc>::push_back(const _Tp&) [with _Tp = Item, _Alloc = std::allocator<Item>]'
item.cpp:170:   instantiated from here
.../3.4.6/bits/vector.tcc:238: error: non-static const member `const char Item::_value', can't use default assignment operator
Bo Persson
  • 90,663
  • 31
  • 146
  • 203
WilliamKF
  • 41,123
  • 68
  • 193
  • 295
  • 1
    I think that should work just fine. I'm wondering why you're talking about `operator=`. It is not called anywhere. – Nawaz Mar 24 '12 at 17:20
  • 1
    `push_back` does not need or call `operator =()` it just makes copies of object being added to the container using the copy constructor.What exactly is the problem? – Alok Save Mar 24 '12 at 17:20
  • @Als See the error message I added. – WilliamKF Mar 24 '12 at 17:32
  • @WilliamKF: Check Dietmar's answer and my comment under it.Every answer or comment except his answer are incorrect. – Alok Save Mar 24 '12 at 17:33
  • A goid implementation of `std::vector` would still insist on `T` being assignable because otherwise the code wouldn't be portable. At least this was the case with C++2003 where `push_back()` typically just called `insert(v, end())`. It seems in C++ 2011 this freedom isn't given to `std::vector<...>`. – Dietmar Kühl Mar 24 '12 at 17:40
  • You error message shows that `push_back()` delegates to the more general `insert()` which possibly needs to make space for an element in the middle of the container. For this it would move objects towards the end using assignment. This definitly a valid C++ 2003 aporoach but seems to be illegal in C++ 2011: try compiling with `-std=c++11` or `-std=c++0x` depending on you version of gcc. Well, 3.4.6 won't have this: consider upgrading to newer version... – Dietmar Kühl Mar 24 '12 at 18:01

1 Answers1

12

For std::vector<T> the elements are required to be Assignable. You type is not Assignable. An implementation of. std::vector<T> could avoid insisting on this requirement but this would be a disservice as the resulting code wouldn't be portable.

You can use a std::list<T> instead or change the definition of you type. For example you can create an accessor to only read the value but no setter. Of course, assignment would change the value. The choice thus is to either allow this change or allow putting the objects into a container. You won't get both.

Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
  • +1 Ah nice answer.Everyone commenting or answering(including me) on this Q missed the point that, The basic requirement of any container is that its elements should be copy constructible and assignable.Probably, everyone was misled by the fact that OP mentioned `push_back()` as an specific case. – Alok Save Mar 24 '12 at 17:29
  • @Als I would like random access, so am using vector instead of list. Once I place the items in the vector, I have no need to modify them. Is there some way to initialize my vector as desired? Other than this one issue, my program compiles fine, so all other uses of the vector are acceptable to the compiler. – WilliamKF Mar 24 '12 at 17:36
  • @Dietmar Kühl While I could make my member non-const I feel it would be inferior as something has gone wrong with my program if the _value is modified after insertion into the vector. What container would give me random access but not require me to give up const members? – WilliamKF Mar 24 '12 at 17:41
  • It seems that C++ 2011 only requires the type to be `CopyInsertable` or to be `MoveInsertable`. In C++ 2003 the type certainly had to be `CopyAssignable`. That is, it may work with a C++ 2011 implementation. – Dietmar Kühl Mar 24 '12 at 17:47
  • @WilliamKF in C++ 2011 it seems all standard containers should work and in C++ 2003 only `std::list` would work but this doesn't have random access. – Dietmar Kühl Mar 24 '12 at 17:50
  • What I mean with "it seems" is that I have looked at all places I currently think are relevsnt and I haven't found any requirement that the template argument for `std::vector` has to be `Assignable` (andI would have argued in favor of this change but I don't recall this discussion). – Dietmar Kühl Mar 24 '12 at 17:53