user974967
user974967

Reputation: 2946

overloading operator[] for a custom vector class

I am creating a class that is similar to a vector. It uses its own algorithm to determine where and how the data is actually stored. From the user's standpoint, it works just like a normal vector.

Internally, it tries to save memory by not storing duplicate values more than once. If the same value is pushed onto the vector more than once, it does some fancy dance moves with the indices but only stores the actual value once.

When overloading operator[], the index argument is converted to the "real" index so it can access where the data is actually stored.

If the user tries to access an element like so:

int i = svec[8];

The correct element is returned by converting 8 to the "real" index and accessing the correct element.

The problem comes in when the user tries to assign a value like so:

svec[8] = 1;

The value 8 will again be covered to the "real" index and a reference to the element is returned by operator[](). However, multiple indices might be mapping to that element. If I return a reference and allow it to be changed, it will have the undesired side effect of changing the value for other indices.

If I just return the element by value, you won't be able to assign a value using operator[].

Within operator[](), I would like to know if an operation plans to change the value of the element so I can create a new element, do some more fancy dance moves with the indices, and return a reference to the new element.

Is anything like this possible? If not, it seems like I'm forced to return by value, thereby preventing the user from modifying the values using [].

Upvotes: 2

Views: 535

Answers (2)

ipc
ipc

Reputation: 8143

It would be easy, if the class would have a method change_element and everybody is calling this function when changing, isn't it?

template <typename T>
struct my_vec {
  T& change_element(int index, T new_value)
  { ... }
};

Now, the idea is to return a proxy class from operator[] that does this job for you.

  // inside my_vec:
  struct proxy {
    my_vec *vec;
    int index;

    T& operator=(T o)
    { return vec->change_element(index, std::move(o)); }

    operator T() const { return (*const_cast<my_vec const*>(vec))[index]; }
  };

  proxy operator[](int i) { return proxy{this, i}; }
  T const& operator[](int i) const { ... }

There is no overhead, every common compiler should optimize the proxy element away.

This trick is even used in the STL by vector<bool>. Check this out for a more complete example.

Upvotes: 3

Daniel
Daniel

Reputation: 31579

You can return a class with convertion operator to the type and an assigment operator that notifies the vector that the element needs to change.

Upvotes: 0

Related Questions