TCPL

B

bashill.zhu

This is a program just for testing operator overloading. But I found
the operator ++ doesn't act like on built-in types. For detail:
When
int array[10];
Ptr_to_T<int> smart_ptr(&array[0], array, 10);
*smart_ptr++ = 10; // I want to modify array[0],but this sentence
modifies array[1]

Do I make myself clear?
Could some body tell me how to fix it ?

#include <iostream>
using namespace std;
template<typename T>
class Ptr_to_T
{
public:
Ptr_to_T(T* p, T* array, int size):_p(p),_array(array),_size(size)
{}
Ptr_to_T(T* p):_p(p){}
Ptr_to_T& operator++(){//prefix
_p += 1;
return *this;
}
Ptr_to_T& operator++(int){//postfix
cout << "Entering Operator++" << endl;
T* temp = _p;
_p += 1;
return *this;
}
T& operator*(){
cout << "Entering Operator*" << endl;
return *_p;
}
private:
T* _p;
T* _array;
int _size;
};
int main()
{
int array[10];
Ptr_to_T<int> smart_ptr(&array[0], array, 10);
*smart_ptr++ = 10;
cout << array[0] << endl;
cout << array[1] << endl;
}


Result:

Entering Operator++
Entering Operator*
4246640
10
 
B

bashill.zhu

This operator increments *this then returns it. What it should do is
make a local copy of *this, increment *this, and return the local copy
by value. Typically, that looks like this:

my_iterator my_iterator::eek:perator++(int)
{
my_iterator temp(*this);
++*this;
return temp;

}

--
Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com) Author of "The
Standard C++ Library Extensions: a Tutorial and Reference
(www.petebecker.com/tr1book)

Thanks all, Got it!

#include <iostream>
using namespace std;
template<typename T>
class Ptr_to_T
{
public:
class Range{};

Ptr_to_T(T* p, T* array, int size):_p(p),_array(array),_size(size)
{
}
Ptr_to_T(T* p):_p(p){}
Ptr_to_T& operator++(){//prefix
_p += 1;
return *this;
}
const Ptr_to_T operator++(int){//postfix
T* temp = _p;
_p += 1;
return Ptr_to_T(temp, temp, _array + _size - temp);
}
T& operator*(){
check();
return *_p;
}
private:
void check(){
if( _p - _array >= _size || _p < _array){
cout << _p - _array << endl;
throw Range();
}
}

T* _p;
T* _array;
int _size;
};
 
J

James Kanze

On 2008-10-04 09:03:30 -0400, "(e-mail address removed)"
<[email protected]> said:
This operator increments *this then returns it. What it should
do is make a local copy of *this, increment *this, and return
the local copy by value. Typically, that looks like this:
my_iterator my_iterator::eek:perator++(int)
{
my_iterator temp(*this);
++*this;
return temp;
}

This is, of course, the difference he was complaining about, but
there is another significant difference: the built-in operator++
requires an lvalue; this overload doesn't. If you really want
to be as close as possible to the built-in types (and think that
it makes a difference), you should define the operator as a
non-member, taking a non-const reference.

Of course, even then, it introduces sequence points which aren't
present with a built-in operator:).

(Seriously, the rule of making a user defined operator behave as
closely as possible to what the built-in operator does is really
only applicable in cases where the built-in operator would be
usable. Trapping accidental use where the built-in operator
would cause an error is a lot less important.)
 
H

Hendrik Schober

James said:
[...] If you really want
to be as close as possible to the built-in types (and think that
it makes a difference), you should define the operator as a
non-member, taking a non-const reference.

What's the difference (besides the different syntax to call
those functions) between
struct X { void f(); };
and
struct X {}; void g(Y&);
?

Schobi
 
J

James Kanze

James said:
[...] If you really want
to be as close as possible to the built-in types (and think that
it makes a difference), you should define the operator as a
non-member, taking a non-const reference.
What's the difference (besides the different syntax to call
those functions) between
struct X { void f(); };
and
struct X {}; void g(Y&);
?

The first can be called on a temporary, the second can't; i.e.:

X().f() ; // legal
g( X() ) ; // illegal

In the case of an overloaded operator, of course, the syntax for
the two calls is the same, e.g. ++X(); if the operator++()
function is a member, it's legal, if it is a free function
taking a non-const reference (which is the only way it could be
a free function), it's not.
 
H

Hendrik Schober

James said:
James said:
[...] If you really want
to be as close as possible to the built-in types (and think that
it makes a difference), you should define the operator as a
non-member, taking a non-const reference.
What's the difference (besides the different syntax to call
those functions) between
struct X { void f(); };
and
struct X {}; void g(Y&);
?

The first can be called on a temporary, the second can't; [...]

Ah, right. I forgot about this.
In the case of an overloaded operator, of course, the syntax for
the two calls is the same, e.g. ++X(); if the operator++()
function is a member, it's legal, if it is a free function
taking a non-const reference (which is the only way it could be
a free function), it's not.

What I thought is that, if 'operator++()' actually changes
its argument (as it is supposed to do), and if it's applied
to a temporary, then this means that an rvalue is changed --
which I thought is UB.
I suppose I'm wrong?

Schobi
 

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

No members online now.

Forum statistics

Threads
473,780
Messages
2,569,608
Members
45,241
Latest member
Lisa1997

Latest Threads

Top