void* used in arithmetics

X

Xavier Decoret

This is a compiler error that I get when I try to do:

void* p;
unsigned int stride;
// ...
p += stride;


I have good reason to do this, namely an iterator over an array of
object whose type may vary, as outlined below. So I don't understand why
it is a compiler error and not only a warning. I can superced this by:
p = ((char*) p)+1;
but I don't like it.

class Type;
class TypeA : public Type; // has as sizeof 10 for example
class TypeB : public Type; // has as sizeof 20 for example

class Parent
{
public:
class Iterator
{
public:
Type* operator->() const { return reinterpret_cast<Type*>(p_); }
Iterator& operator++() { p_ += stride_; return *this; }
protected:
friend class Parent;
Iterator(void* p,int s) : p_(p),stride_(s) {}
private:
void* p_;
int stride_;
}
protected:
template <class T>
Iterator iterator(const T* t)
{
return Iterator(t,sizeof(T));
}
};


Then I can have sublclasses of Parent using vectors of TypeA or TypeB on
which I can iterate using the Type interface thru the Parent interface.

--
+-------------------------------------------------+
| Xavier Décoret - Post Doct |
| Graphics Lab (LCS) - MIT |
| mailto: (e-mail address removed) |
| home : http://www.graphics.lcs.mit.edu/~decoret|
+-------------------------------------------------+
 
J

Jack Klein

This is a compiler error that I get when I try to do:

void* p;
unsigned int stride;
// ...
p += stride;


I have good reason to do this, namely an iterator over an array of
object whose type may vary, as outlined below. So I don't understand why
it is a compiler error and not only a warning. I can superced this by:
p = ((char*) p)+1;
but I don't like it.

Your reasons might or might not be good, but neither C nor C++ have
ever allowed this, and they never will. A pointer is not just a
number, it has additional qualities, namely the size of the type
pointed to.

If you add 1 to a pointer to char, the pointer points to the next char
(next byte).

But if you add 1 to a pointer to int, the pointer points to the next
int, so the actual address increases by sizeof(int). If you have a
pointer to a struct or a class with a size of 10 bytes, adding 1 to
that pointer causes the actual memory location pointed to to change by
10 bytes.

Pointers are not integer types, and do not behave like integer types.

To perform arithmetic on any pointer type, it must be a pointer to a
complete type, meaning that the compiler must have a definition for
the type in scope from which it can determine the size of the type.

"void" is an incomplete type which cannot be completed.

You can't perform arithmetic on pointers to any incomplete type.
That's just the way it is, the way it has always been, and almost
certainly the way it's going to stay.

Pointers to the character types are pointers to complete types, and
objects of these types (signed, unsigned, or "plain" char) are
ordinary bytes. The conversion of a pointer to void into a pointer to
any of the character types is guaranteed to leave the representation
unchanged, and then you can do arithmetic using the size of objects,
which is also expressed in terms of bytes.
class Type;
class TypeA : public Type; // has as sizeof 10 for example
class TypeB : public Type; // has as sizeof 20 for example

class Parent
{
public:
class Iterator
{
public:
Type* operator->() const { return reinterpret_cast<Type*>(p_); }
Iterator& operator++() { p_ += stride_; return *this; }
protected:
friend class Parent;
Iterator(void* p,int s) : p_(p),stride_(s) {}
private:
void* p_;
int stride_;
}
protected:
template <class T>
Iterator iterator(const T* t)
{
return Iterator(t,sizeof(T));
}
};


Then I can have sublclasses of Parent using vectors of TypeA or TypeB on
which I can iterate using the Type interface thru the Parent interface.

If you want to perform this sort of low-level pointer manipulation you
have no choice but to convert to pointer to one of the character
types. The language does not allow adding integers to pointer to void
because it would have to multiply the integer by sizeof(void), which
is not defined.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++ ftp://snurse-l.org/pub/acllc-c++/faq
 
J

John Dibling

object whose type may vary, as outlined below. So I don't understand why
it is a compiler error and not only a warning. I can superced this by:

Because the compiler doesn't know how far to move the pointer. If the
void* is an array of char, it would move it 1 byte for every
increment. On the other hand, if the void* points to an array of
double, it wouldn't have to move by one byte anymore, because a double
takes more than 1 byte of memory.

You must cast as you did in your sample. Sorry you don't like it, but
that the glamorous life of a C++ programmer...

</dib>

John Dibling
email: dib@substitute_my_full_last_name_here.com
Witty banter omitted for your protection
 

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,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top