Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ Use Unassignable Objects in Vector

I want to store a list of objects in an std::vector, but the objects contain a reference and cannot be assigned to. I can, however, copy-construct the object.

The only option I can think of is to use pointers to wrap the objects and reseat the pointers when they need to be assigned, but the syntax for this would significantly reduce readability, especially when using iterators, and I would prefer an alternative.

Doesn't work:

std::vector<MyObject> myVector;
//fill the vector
//...
myVector[1] = object1;

Smart pointers sacrifice readability:

std::vector<std::unique_ptr<MyObject>> ptrVector;
//fill the vector
//...
ptrVector[1] = std::unique_ptr<MyObject>(new MyObject(object1));

Are there any other methods to use unassignable objects in an std::vector?

like image 253
Elliot Hatch Avatar asked Nov 03 '22 14:11

Elliot Hatch


1 Answers

This isn't a direct answer to your question as I can't offer a replacement for std::vector, or a different way of using it that allows you to do what you need to.

However, if it is possible to modify the definition of MyObject, it may be an option to change it so it uses std::reference_wrapper instead of conventional references. That would allow MyObject to be assignable.

Example:

#include <vector>
#include <functional>
#include <iostream>

struct MyObject
{
  //int &_i;
  std::reference_wrapper<int> _i;
  MyObject(int &i):_i(i) {}
};


int main() {
  std::vector<MyObject> vec;
  int i1 = 3;
  int i2 = 4;
  MyObject c1(i1);
  MyObject c2(i2);

  /* Storing object. */
  vec.push_back(c1);

  /* Assigning to it. */
  vec[0] = c2;

  /* Confirming that it's the correct object now. */
  for (const MyObject &it : vec)
    std::cout << it._i << std::endl;

  /* Modifying the value of its internal reference. */
  vec[0]._i.get() = 5;
  /* Confirming that the original int changed value indeed. */
  std::cout << "i2 == " << i2 << std::endl;

  return 0;
}

Caveat: Existing code may already contain direct assignments to the reference member (i.e. the member called _i in the code above). Those assignments were intended to change the value of the object the reference refers to. When replacing the reference with a std::reference_wrapper, all direct assignments _i = x must be replaced with _i.get() = x, otherwise the semantics of the program change entirely.

(EDIT) If the references used are const-references const T&, a std::reference_wrapper<const T> can be used. Using the example above, the definition of MyObject then changes to this:

struct MyObject
{
  std::reference_wrapper<const int> _i;
  MyObject(const int &i):_i(i) {}
};
like image 135
jogojapan Avatar answered Nov 11 '22 08:11

jogojapan