How to define []= and at() = for a custom collection? - c++

EDIT: This question is not for overriding the operator [] I know how to do that
I have implemented My own collection class, and for assigning data I would like to provide the same operators/functions as std::vector.
However, I have not been able to find a way to define the operators [index]=elm and at(index) = elm.
I am not even completely sure what to terms to search for as these two are not exactly operators

Define your operator[] overload and your at function to return a reference to the specified item. You can then assign the new value through that reference.

There is no []= operator. If your operator[] function returns a reference that can be assigned to, that's all you need.
Simple example to demonstrate the idea.
struct Foo
{
int i;
int& operator[](int) { return i; };
int operator[](int) const { return i; };
}
Now you can use
Foo f;
f[10] = 20; // The index is not used by Foo::operator[]
// This is just to demonstrate the syntax.
You need to do the same with the at() function.

Related

C++, operator [], and tracking a change

I'm trying to build a little array-ish class, like so:
class dumb
{
bool mChanged=false;
int mData[1000];
int& operator [](int i) {return mData[i];}
};
Here's my question-- is there any kind of hack or trick I could do so that if I did this:
dumb aDumbStuff;
aDumbStuff[5]=25; <- now mChanged gets set to true!
So basically, I want my class's mChanged value to go true if I modify any content. Any way to do this without making the array itself an array of objects that they themselves track getting changed, or by doing memcmps to see if things changed at all?
Some complex dance of assignment operators that would let my class detect "[n]=" happening?
The usual solution is to use a helper class, something like:
struct inner_ref {
dumb &me;
int i;
inner_ref(dumb &, int);
operator int();
dumb &operator=(int);
};
The operator[] overload returns this object, constructing it using a reference to *this, and the passed-in array index. Its operator= overload executes the actual assignment and also sets this flag. Its operator int() provides the appropriate semantics when [] is used to access the array's value, rather than modifying it.
You could set the flag to 'changed' inside your existing operator[] method, and add a second version with const returning an int (= not as a reference):
int operator [](int i) const {return mData[i];}
The compiler would pick the right one - modifying or not, as needed!

About using returned references

I'm having some trouble trying to understand proper usage of returned references in C++.
I have a class with a "big" object inside. I want to be able to use this object outside the class "read only" mode by returning a const reference to it.
The problem is I don't quite understand when objects get copied and when they don't.
Most of the questions about returning references where about returning objects allocating on the stack, which is not my particular problem, so I've prepared this little example:
class foo {
int a;
public:
foo() {
a = 3;
}
int& getInt() {
return a;
}
const int& useInt() {
return a;
}
void print() {
cout << "Inside class: a = " << a << endl;
}
};
int main() {
foo foo1;
int& goodRef = foo1.getInt();
int badRef = foo1.getInt();
goodRef = 4;
badRef = 5;
foo1.print();
foo1.getInt() = 6;
foo1.print();
int usingIt = 10*foo1.useInt();
}
What I understand is:
In int& goodRef = foo1.getInt(); nothing is copied, only the class owned a exists.
In int badRef = foo1.getInt(); badRef is a copy of a, so there are 2 separate objects, a and badRef.
So depending on what type of object catches the return value it is copied or it is not, so my question is:
When I use the reference like in int usingIt = 10*foo1.useInt(); is it copied and then used to multiply or only the value inside the class is used?
In this example it doesn't matter since it is only an int, but if it was a big object it would be a big deal.
Thanks!
Edit: Thanks to all the answers, but I get that having such methods inside a class is bad, I only put them for the sake of the example.
My actual class has a bunch of objects inside and an interface and bla bla, but one particular object is a glm::mat4. What i want is to be able to write something like glm::vec4 finalVec = foo1.getMatrix() * vec. But I dont want the whole matrix to be copied and then multiplied, rather I want to use the matrix that is already inside my class to perform the multiplication and at the same time not let the user modify it. I supposed something similar to useInt but with the mat4 would work but I wasn't sure and that's why I asked the question.
The glm specificatioon is very confuse for me, but I think the operator * is described as:
glm::mat4 operator* (glm::mat4 const & m, glm::vec4 const & v);
In your example int usingIt = 10*foo1.useInt();, the operator*(), depending on it's argument signature and internals, could cause a copy of your object to take place, at which point it would then be assigned (rather than copied again) into the value of usingIt. If your object was an aggregate or class object type, the copy using the object type's assignment operator would typically be elided using a compiler optimization step.
In general, anytime you are copying a l-value reference type (i.e., T& or const T&) to an aggregate or class object to a non-reference type (i.e., type T), a copy constructor, constructor, assignment operator, or conversion operator is invoked on the returned reference to the object.
If getInt returns int& why are you catching the return value in an int? What do you expect, that the compiler changes your source code to use a reference to int? It can't do anything else than copying the value of the object pointed by the reference.
On the other hand I think you have a bad example. Either you define a single method that returns a const reference:
int const & getInt() { return a; }
Or you provide two methods, one const and one non const:
int& getInt() { return a; }
int const & getInt() const { return a; }
Having both getInt and useInt does not stop anyone from using getInt and actually changing the value of the object in an way that is not intended.
When you use const reference you can only use const methods of this object. E.g. when you have STL vector you can get size, but you can't push_back elements to it.
vector<int> a;
vector<int> &c = a;
const vector<int> &b = a;
a.size();
b.size();
a.push_back(4);
c.push_back(4);
//our vector is now 4 4
//b.push_back(4); compilation error
In C++ you copy when you want to copy: for example
Function which copies:
int x(vector<int> b)
Function which doesn't copy:
int x(vector<int> &b)
You can read more here

How to simplify usage of overloaded subscript operator via pointer?

I have a class Foo that encapsulates access to a vector and provides access to it via the subscript operator:
typedef int* IntPtr;
class Foo {
std::vector<IntPtr> bars;
IntPtr& operator[](size_t idx) {
return bars[idx];
}
};
In class Bar i want to use Foo. While solution 1 works, it is rather inconvenient. I would prefer something like solution 2. Obviously, a method call (even if it returns an lvalue) can't be assigned something, albeit the method call doesn't do anything else than solution 1.
class Bar {
Foo *foo; //some initialization
IntPtr helper(size_t idx) {
return (*foo)[idx];
}
void barfoo() {
size_t baz = 1;
IntPtr qux;
//solution 1
qux = (*foo)[baz]; //works
(*foo)[baz] = &1; //works
//solution 2
qux = helper(baz); //works
helper(baz) = &1; //does not work: "expression is not assignable"
}
};
Question: How can I simplify the usage of an overloaded subscript operator?
EDIT: Changed used type to from int to int*. Sorry, I screwed up when creating the example.
I guess the problem is because of the twisted int*&.
The best way is to write a regular method, e.g Foo::at(size_t idx), providing the same functionality as your operator.
Notice that the STL does the same (just take a look at std::vector).
You can then simply call foo->at(baz);. To avoid rendundancy you could change the implementation of operator[]:
int& operator[](size_t idx) {
return at(idx);
}
In your snippet, you cant assign a value to the return because you have forgotten to return a reference.
Not that nice but an alternative would be foo->operator[](baz); though I strongly discourage you to write such an ugly code.
Darn. I just forgot to let helper return the value via a reference:
IntPtr& helper(size_t idx)
or
int*& helper(size_t idx)

Overloading function call operator and assignment

In a project of mine, I'm writing a wrapper for std::vector. I'm doing this because I am using homogeneous coordinates and for some operations it's just easier to temporarily 'forget' the fourth coordinate.
Now I stumbled upon a problem. I have loads of assignments like the following:
Vector v;
v(0) = 5;
v(1) = 6;
and so on. I also want to do the following:
double x;
x = v(0);
For that last thing, I can overload the () operator, but how would implement the first thing? (the zero and one being an index).
Just return reference.
class Vector
{
int data[4];
int & operator() (int index) { return data[index]; }
};
Return a non-const reference to the element to be modified.
Two things-
You should probably be overloading operator[] to do this rather than operator(), since it's the more natural operator here. operator() is used to create function objects, while operator[] is the operator meaning "pick out the element at this position."
You can support assignment to the result of operator[] / operator() by having the function return a reference to the value that should be written to. As a simple example, here's some code that represents a class wrapping a raw array:
(code here:)
class Array {
public:
int& operator[] (unsigned index);
int operator[] (unsigned index) const;
private:
int array[137];
};
int& Array::operator[] (unsigned index) {
return array[index];
}
int Array::operator[] (unsigned index) const {
return array[index];
}
The second of these functions is a const overload so you can have const Array read but not write values.
In the standard libraries, such things are implemented by having operator() (well, actually usually operator[]) return type double &. By returning a reference to a double, you can assign to or from it.
However, are you sure you want to wrap this around std::vector? This class is not a vector in the mathematical sense; it's much like a Java ArrayList, and so not at all efficient for small structures. Usually when I'm writing my own vector classes I'm planning on having lots of them around, so I implement a class from scratch on top of a static array.

Accessing vector in class

If I have a vector as a private member in my class, what's the best way to access it? For example, take the following simple class
class MCL{
private:
std::vector my_vec;
public:
// Include constructor here and other member functions
}
What's the best way to access my_vec? Specifically, I would like to use a getter function to access it.
return it by const reference, or just by reference if you want to allow changing.
const std::vector<T> & getVector() const
{
return vector;
}
usage:
const std::vector<T> &v = myClass.getVector();
Create a public function called
std:vector getMyVec() {return my_vec;}
Depending on the semantics of your class, you may want to implement operator[]:
T& operator[](int i) {
return my_vec[i];
}
This way you can user [] to access the contents of your vector:
MCL a;
a[0] = 3;
std::cout << a[0] << std::endl;
Note that this may be considered abuse of operator[] or bad practice, but it is up to the developer to judge if this construct fits in the class, depending on its semantics.
Also note that this solution does not provides a way to insert or delete elements from the vector, just access to the elements already there. You may want to add other methods to do these or to implement something like:
T& operator[](int i) {
if(my_vec.size() < i)
my_vec.resize(i+1);
return my_vec[i];
}
Again, it is up to the semantics of your class and your usage pattern of it. This may or may not be a good idea.