Page 1 of 2

inc/dec operator return a pointer?

Posted: Thu Sep 20, 2007 8:50 am
by eboyd
Does anyone know if it's possible to overload the increment/decrement operators to return a pointer?

Looking through a lot of documentation it seems they can only return an (int). But i think it would be pretty darned cool if you could write:

Code: Select all

myPointer++;
as opposed to:

Code: Select all

myPointer = myPointer->next;

Posted: Thu Sep 20, 2007 9:23 am
by AJ
Hi,

AFAIK, it already happens:

Code: Select all

unsigned long *x = (unsigned long*)myval;
x++;
Assuming a long size of 4 bytes, x will be incremented by 4.

Code: Select all

struct MyStruct *x = (struct MyStruct*)myval;
x++;
Here, x will be incremented by sizeof(struct MyStruct).

Are you actually meaning that you want the same thing to work for a linked list? If so, I don't see why it wouldn't be possible - but I don't know how advisable this would be.

Cheers,
Adam

Posted: Thu Sep 20, 2007 9:26 am
by RedEagle
Hi
outof an german tutorial:
// C++ Kurs
// Beispiel zu ueberladenen Operatoren

// Klassendefinition
class Rect
{
short xPos, yPos; // Position
short width, height; // Breite und Hoehe
public:
Rect(); // ctors
Rect(short x, short y, short w, short h);
Rect operator ++(int); // Verschiebt Rechteck um eine X/Y-Position
};
// Definition der Memberfunktionen
// 1. Konstruktor (Standard Konstruktor)
Rect::Rect()
{
xPos = yPos = width = height = 0;
}
// 2. Konstruktor
// Erhaelt als Parameter die Rechteck-Daten als 4 short Werte
Rect::Rect(short x, short y, short w, short h)
{
xPos = x; yPos = y;
width = w; height = h;
}
// Verschiebt Rechteck um eine X/Y-Position
// Achtung Postfixoperator!
// Darf keine const-Memberfunktion sein da das Objekt
// ja veraendert wird!
Rect Rect::operator ++(int)
{
// Hilfsobjekt zur Aufnahme der akt. Werte
// Ruft copy-ctor auf
Rect orig(*this);
// Nun erst Position veraendern
xPos++;
yPos++;
// Ursprungswerte zurueckgeben
return orig;
}

Posted: Thu Sep 20, 2007 9:46 am
by eboyd
Are you actually meaning that you want the same thing to work for a linked list? If so, I don't see why it wouldn't be possible - but I don't know how advisable this would be.
Yea, I was meaning this. I was thinking that would be an interesting way to handle list traversal. Something like this:

Code: Select all

myClass *curr;
while(curr != something; curr++)
{
     // do stuff
}
I've never seen it done that way, so I'm guessing either it's not possible, or not suggested.

Posted: Thu Sep 20, 2007 9:53 am
by eboyd
Rect Rect::operator ++(int)
{
// Hilfsobjekt zur Aufnahme der akt. Werte
// Ruft copy-ctor auf
Rect orig(*this);
// Nun erst Position veraendern
xPos++;
yPos++;
// Ursprungswerte zurueckgeben
return orig;
}
I'm assuming this returns the deep copy of xPos & yPos, but incremented by the postfix increment operator.

But (*this) doesn't return a pointer. I want a pointer.

In a list class, if you have a next and prev pointers (for traversal purposes mainly) I would like to say p++; and get p = p->next; Or p--; and get p = p->prev;

Posted: Thu Sep 20, 2007 9:58 am
by AJ
OK,

Does >> this << help?

Cheers,
Adam

Posted: Thu Sep 20, 2007 10:12 am
by eboyd
This compiles:

Code: Select all

node operator++(int)
{
    node* curr = curr->next;
    return curr;
}
But crashes when I use it:

Code: Select all

void someFuncion()
{
    ...
    curr++;
    ...
}

Posted: Thu Sep 20, 2007 10:37 am
by Candy
eboyd wrote:This compiles:

Code: Select all

node operator++(int)
{
    node* curr = curr->next;
    return curr;
}
But crashes when I use it:

Code: Select all

void someFuncion()
{
    ...
    curr++;
    ...
}
curr is null when you dereference it for next. It's an at that point uninitialized local variable.

Try making a class, say, iterator, that does what you just described.

Code: Select all

#include <list>
#include <iostream>
using std::cout; 
using std::endl;
using std::list;
typedef std::list<int>::iterator iterator;

int main() {
   list<int> numberlist;
   numberlist.push_back(1);
   numberlist.push_back(2);
   numberlist.push_back(3);
   for (iterator i = numberlist.begin(); i != numberlist.end(); ++i) {
      cout << *i << endl;
   }
}
Analog:

Code: Select all

#include <iostream>
using std::cout; 
using std::endl;

int main() {
   int numberlist[3] = { 1, 2, 3 };
   for (int * i = numberlist; i != numberlist + 3; ++i) {
      cout << *i << endl;
   }
}

Posted: Thu Sep 20, 2007 12:35 pm
by Solar
It's done easily enough:

Code: Select all

#include <iostream>
class Foo
{
    public:
        Foo() : mNext( 0 ) {};
        Foo( Foo * foo ) : mNext( foo ) {};
        Foo * operator++( int ) { return mNext; }
    private:
        Foo * mNext;
};

int main()
{
    Foo x;
    Foo y( & x );
    std::cout << &x << std::endl;
    std::cout << y++ << std::endl;
    return 0;
}
However, operator overloading really should keep the semantics of its native counterparts intact. Look at the example main() - why is x an object, but (y++) a pointer to object? This is pretty easy to get messed up with...

Posted: Thu Sep 20, 2007 1:15 pm
by eboyd
alright, this is basically my class setup:

Code: Select all

template <typename T> class dlist
{
     struct type
    {
        ...
        T data;
        type *next, *prev
        ...
        type* operator++( int ) // for postfix incrementer
     };

     ...
};
The above compiles, but crashes when I use it. Am I declaring it wrong, or in the wrong place?


Why do you return a pointer to an object of class type when you invoke operator++ on an object of class type? What about returning a reference to an object of class type instead?

Ignore the iterator reference, we'll get to that later.

Posted: Thu Sep 20, 2007 3:01 pm
by Solar
eboyd wrote:The above compiles...
I doubt it, since at least two semicolons and an implementation for operator++() are missing. Could you provide some more code, which actually compiles and exhibits the problems you're having?

Posted: Fri Sep 21, 2007 9:42 am
by eboyd
I hope this isn't way too long:

Code: Select all

template < typename T > class dlist
{      
    public:
   
        dlist() : head( new type( T() ) ), tail( new type( T() ) ) {}
        
        dlist( const dlist& src ) : head( new type( T() ) ), tail( new type( T() ) )
        {
            clear();

            for( type* temp = ( src.head )->next; temp != src.tail; temp = temp->next )
            {
                pushb( temp->data ) ;
            }
        }
        
        ~dlist()
        {
            clear();
            delete head;
            delete tail;
        }
       
       /*  I've omitted all my member functions to save space here. */

    private:
        
        struct type
        {   
            type( const T& x, type* y = 0, type* z = 0 ) : data( x ), prev( y ), next( z ) {}
            
            type( const type& src ) : data( src.data ), prev( src.prev ), next( src.next ) {}
        
            type* operator++( int )
            {
                return next;
            }
            
            T data;
            type *prev, *next;
        };
        
        type *head, *tail;   
};
Here's an example in my defnitions that will cause a crash when called in main():

Code: Select all

/*    This simply reverses the order of the list.
*/
template <typename T> void dlist<T>::rev()
{
    if(!empty())
    {
        type* curr = head->next;
        int sz = size();
        
        while(curr != tail)
        {
            T temp = curr->data;
            pushf(temp);
            curr++;    // this is in place of "curr = curr->next"
        }
       
        for(int i = 0; i < sz; i++)
        {
            popb();    // trim the left-over fat
        }
    }
}
I've also omitted my assignment operators for both "dlist" & "type" to save space since both contain "try-catch" blocks.

I've tried several different versions of the increment operator, most of which compile, but crash when used.

The one in my code here implements your suggestion.

Posted: Sat Sep 22, 2007 3:36 am
by Solar
Does it work when you replace curr++ with curr = curr->next?

Posted: Sat Sep 22, 2007 7:04 am
by eboyd
Does it work when you replace curr++ with curr = curr->next?
Yes, that works. That's how I normally would handle traversal.

But what I'm trying to figure out is if

Code: Select all

curr++;
can do the dame thing as

Code: Select all

curr = curr->next;

Posted: Tue Sep 25, 2007 11:56 am
by Candy
eboyd wrote:
Does it work when you replace curr++ with curr = curr->next?
Yes, that works. That's how I normally would handle traversal.

But what I'm trying to figure out is if

Code: Select all

curr++;
can do the dame thing as

Code: Select all

curr = curr->next;
Yes. But, only if curr is not a pointer or you satisfy other special conditions that a list cannot.

Make curr an object of some type and call operator++ on that object. Curr may not be a pointer.