index operator[] overloading

B

Bart Simpson

Can anyone explain how this works. How may I implement this?

I want to be able to use the operator on both lhs and rhs of assignment
statements. The rhs is a no-brainer (at least I think I got it right):

class MyArray
{
public:
MyArray(const size_t size):m_size(size){ arr_ = new double[size]; }
~MyArray(){ if (arr_) delete[] arr_ ;}

double operator[](const size_t idx)
{ if (idx < m_size)
return arr_[idx];
throw std::exception
}

private:
MyArray(const MyArray&);
operator= (const MyArray&);

double *arr_ ;
size_t m_size ;
}


I read somewhere that the type returned from the [] operator must be a
reference, but I did not quite follow the reasoning/logic - anyone care
to explain ?
 
Z

Zeppe

Bart said:
I read somewhere that the type returned from the [] operator must be a
reference, but I did not quite follow the reasoning/logic - anyone care
to explain ?

A reference is a variable that relates to another variable. for example

int x = 0;
int& y = x;
y = 1;

at the end, x will have a value of 1, because y refers to the same
memory location as x, so it's bind to the x value until the end of its
scope (that hopefully is before or at the same time as the x one :)

In your case it's exactly the same: if you return a reference, you are
returning a (temporary) variable that refers to the address of the
element that you want to modify. So, if you assign a value to this
variable (that would be prohibited if it wasn't a reference, because is
a temporary), the value will be written in the memory location of your
array element.

that's it!

Regards,

Zeppe
 
B

Bart Simpson

Thanks Zeppe that clarifies that.

So to implement it one has to implement BOTH of these?

myType operator[](const size_t) const;
myType& operator[](const size_t);
 
Z

Zeppe

Bart said:
Thanks Zeppe that clarifies that.

So to implement it one has to implement BOTH of these?

myType operator[](const size_t) const;
myType& operator[](const size_t);

exactly, and the compiler will chose the proper one based on the
"const". Another hint: the method

myType operator[](const size_t) const;

makes a copy of the element that it returns, which can be undesirable if
the objects myType are big. So, it usually common to do

const myType& operator[](const size_t) const;
myType& operator[](const size_t);

if you return a const reference, you can't use it in the left side of
the assignment, and you avoid the copy on the return.

Regards,

Zeppe
 
B

Bart Simpson

Zeppe said:
Bart said:
Thanks Zeppe that clarifies that.

So to implement it one has to implement BOTH of these?

myType operator[](const size_t) const;
myType& operator[](const size_t);


exactly, and the compiler will chose the proper one based on the
"const". Another hint: the method

myType operator[](const size_t) const;

makes a copy of the element that it returns, which can be undesirable if
the objects myType are big. So, it usually common to do

const myType& operator[](const size_t) const;
myType& operator[](const size_t);

if you return a const reference, you can't use it in the left side of
the assignment, and you avoid the copy on the return.

Regards,

Zeppe

Thanks!
 
P

Project X

Bart said:
Thanks Zeppe that clarifies that.
So to implement it one has to implement BOTH of these?
myTypeoperator[](constsize_t)const;
myType&operator[](constsize_t);

exactly, and the compiler will chose the proper one based on the
"const". Another hint: the method

To the much of my surprise, I tried this and the non-constant version
is always called. Here is the code:

#include <iostream>

class MyArray
{
public:
MyArray(const size_t size) : m_size(size) {
arr_ = new double[size];
}

~MyArray() {
if (arr_) delete[] arr_ ;
}

double& operator[](const size_t idx)
{
std::cout << "LHS" << std::endl;
return arr_[idx];
}

const double& operator[](const size_t idx) const
{
std::cout << "RHS" << std::endl;
return arr_[idx];
}

double *arr_;
size_t m_size;
};

int main(int argc, char** argv) {
MyArray a(3);
a[0] = 8.0;
std::cout << a[0] << std::endl;
return 0;
}

The output in both cases is "LHS". What's wrong?

-Mustafa
 
V

Victor Bazarov

Project said:
Bart said:
Thanks Zeppe that clarifies that.
So to implement it one has to implement BOTH of these?
myTypeoperator[](constsize_t)const;
myType&operator[](constsize_t);

exactly, and the compiler will chose the proper one based on the
"const". Another hint: the method

To the much of my surprise, I tried this and the non-constant version
is always called. Here is the code:

#include <iostream>

class MyArray
{
public:
MyArray(const size_t size) : m_size(size) {
arr_ = new double[size];
}

~MyArray() {
if (arr_) delete[] arr_ ;
}

double& operator[](const size_t idx)
{
std::cout << "LHS" << std::endl;
return arr_[idx];
}

const double& operator[](const size_t idx) const
{
std::cout << "RHS" << std::endl;
return arr_[idx];
}

double *arr_;
size_t m_size;
};

int main(int argc, char** argv) {
MyArray a(3);
a[0] = 8.0;
std::cout << a[0] << std::endl;
return 0;
}

The output in both cases is "LHS". What's wrong?

Nothing. 'a' is declared non-const. Why would a const function
be called when non-const is available?

V
 
P

peter koch

Bart said:
Thanks Zeppe that clarifies that.
So to implement it one has to implement BOTH of these?
myTypeoperator[](constsize_t)const;
myType&operator[](constsize_t);
exactly, and the compiler will chose the proper one based on the
"const". Another hint: the method

To the much of my surprise, I tried this and the non-constant version
is always called. Here is the code:

#include <iostream>

class MyArray
{
public:
MyArray(const size_t size) : m_size(size) {
arr_ = new double[size];
}

~MyArray() {
if (arr_) delete[] arr_ ;
}

double& operator[](const size_t idx)
{
std::cout << "LHS" << std::endl;
return arr_[idx];
}

const double& operator[](const size_t idx) const
{
std::cout << "RHS" << std::endl;
return arr_[idx];
}

double *arr_;
size_t m_size;

};

int main(int argc, char** argv) {
MyArray a(3);
a[0] = 8.0;
std::cout << a[0] << std::endl;
return 0;

}

The output in both cases is "LHS". What's wrong?

Your program works fine. When the compiler chooses between operator[]
(const size_t idx) and operator[](const size_t idx) const, it makes
its determination based on whether the object in question is const or
not. Since your "a" is non-const, it will always choose the non-const
operator. Try e.g. adding this function and call it:

void f_const(MyArray const& a)
{
a[0];
}

then compare it with


void f_non_const(MyArray& a)
{
a[0];
}

/Peter
 
J

Jerry Coffin

Thanks Zeppe that clarifies that.

So to implement it one has to implement BOTH of these?

myType operator[](const size_t) const;
myType& operator[](const size_t);

You probably need a Proxy. See _More Effective C++_, Item 30.
 
L

Lionel B

Thanks Zeppe that clarifies that.

So to implement it one has to implement BOTH of these?

myType operator[](const size_t) const; myType& operator[](const
size_t);

You probably need a Proxy.
Why?

See _More Effective C++_, Item 30.

Um... not everyone has that book...
 
J

Jerry Coffin

[email protected] says... said:
myType operator[](const size_t) const; myType& operator[](const
size_t);

You probably need a Proxy.

Why?

Because it works quite nicely in this situation, and attempts at doing
the job without a proxy won't.
Um... not everyone has that book...

If they want to deal with this subject, it's worth getting. Seriously,
that item starts on page 213 and ends up page 228. That's far too much
material to attempt to reproduce in a Usenet post -- especially since
(at least if memory serves) it contains references to other parts of the
book as well, so a standalone post would need to contain still more.

Almost anybody getting beyond the basics of C++ should get (probably all
of) Scott Meyers' books -- _Effective C++_ (currently in the third
edition, I believe) is definitely the best of them, but _More Effective
C++_ and _Effective STL_ are worth getting as well. Alternatively, the
_Effective C++ CD_ delivers essentially the same content as the first
two books in electronic form for a bit less money and a lot better
searching -- besides it lets you help support "a man with hair worthy of
Kevlin Henney" (sorry, that's a little bit of a reversed, inside joke,
but if Scott or Kevlin reads this, they'll probably laugh.)
 
J

Jerry Coffin

[ ... ]
Won't work in what way?

Won't invoke the correct version of the operator (const vs. non-const)
in the right situation -- in particular, in the right side of an
assignment, you want the const operator called, and in the left side,
you want the non-const operator called. Overloading the operators
directly, the one that gets called is based on whether the object is
const or not -- for example, if it's not const, the non-const operator
is called even on the right side of the assignment.
 
L

Lionel B

[ ... ]
Won't work in what way?

Won't invoke the correct version of the operator (const vs. non-const)
in the right situation -- in particular, in the right side of an
assignment, you want the const operator called, and in the left side,
you want the non-const operator called.

Do I? How do you know?
Overloading the operators
directly, the one that gets called is based on whether the object is
const or not -- for example, if it's not const, the non-const operator
is called even on the right side of the assignment.

But perhaps that's what I want... ok, most of the time I probably don't,
but you can't assume that.
 
J

Jerry Coffin

[ ... ]
Do I? How do you know?

The same way I know that you want your operator= to return *this, that
you don't want your destructors to throw exceptions, and so on.
But perhaps that's what I want... ok, most of the time I probably don't,
but you can't assume that.

In point of fact, experience indicates that it's quite a safe
assumption. Yes, when people overload operator[] for completely
different purposes (e.g. Boost.spirit) it's sometimes reasonable to do
things entirely differently. When you're using it for subscripting,
however, this is an "assumption" about the same way it's an
"assumption" that the sun will rise tomorrow morning.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,073
Latest member
DarinCeden

Latest Threads

Top