Topic: idea: new pointer type any*


Author: sbnaran@fermi.ceg.uiuc.edu (Siemel Naran)
Date: 1998/08/28
Raw View
On 28 Aug 1998 16:42:42 GMT, Christopher Eltschka

>What about a new pointer type any*, which is the "opposite" to void*,
>in that it can be implicitly converted into any pointer types, but
>no pointer type can be implicitly converted to any*. This would be

The main problem with this Any* is that it looks a little like
overloading by return type.  Kind of like this:
   int   * NULL() { return (int   *)0; }
   double* NULL() { return (double*)0; }
The determination of which overloaded function to use depends
on the context in which the result is used.  If you say
"int* i=NULL()" then the first 'NULL' is called.  The only
difference is that here the function call notation '()' is
not necessary as NULL (and Any) would be built in to the
language.

We actually can do this, but I don't think it's good style.

struct Any
{
     void* ptr;
     Any(void* ptr_) : ptr(ptr_) { }
     template <class T> operator T*() const { return (T*)ptr; }
};

inline Any myalloc(size_t size) { return Any(malloc(size)); };

double* d=myalloc(100);
int   * i=myalloc(100);


Besides, putting in a reinterpret_cast serves as a reminder that
we're working with low-level code.  All type conversions should
be explicit so that we can be careful about what is going on.

double* d=reinterpret_cast<double*>(malloc(100));
int   * i=reinterpret_cast<int   *>(malloc(100));



>for functions like malloc, which could be defined as
>
>and then could be used in C++ as in C like
>
>char* p=malloc(1000);
>
>without a cast, but without destroying the safety of void*.
>any* would be the type that raw memory allocation function should
>return.

But operator new[] already does this!  First, it calls
  void* operator new[](...)
to find space.  Then it casts the resulting space from
void* to whatever*.  So it is a sort of overloading by
return type too, but I guess that's ok here.


--
----------------------------------
Siemel B. Naran (sbnaran@uiuc.edu)
----------------------------------


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1998/09/02
Raw View
Siemel Naran wrote:
>
> On 28 Aug 1998 16:42:42 GMT, Christopher Eltschka
>
> >What about a new pointer type any*, which is the "opposite" to void*,
> >in that it can be implicitly converted into any pointer types, but
> >no pointer type can be implicitly converted to any*. This would be
>
> The main problem with this Any* is that it looks a little like
> overloading by return type.  Kind of like this:
>    int   * NULL() { return (int   *)0; }
>    double* NULL() { return (double*)0; }

I don't see that. Would you see automatic conversion of T* to void*
as overloading on return type as well, since you can do

int* f();

int* a=f();
void* b=f();

and what about conversion float->double or between integral types?

(And is the analoguous behaviour of void* in C overloading on return
type as well?)

Also I wonder what you meant with your NULL function - this would
be a very incompatible change (NULL is currently a macro which
may be a constant zero of any type in C and C++, and in addition
it may be ((void*)0) in C).
Indeed the main reason for any* is compatibility to C, since in
C it is quite commmon to do something like

int* p = malloc(20*sizeof(int));

and with malloc returning the new any* type, this would continue
to work under C++. As a nice side effect it would improve type
safety in C++ for NULL, since now NULL could be defined as
((any*)0), analoguous to the C definition ((void*)0).

[...]

>
> We actually can do this, but I don't think it's good style.
>
> struct Any
> {
>      void* ptr;
>      Any(void* ptr_) : ptr(ptr_) { }
>      template <class T> operator T*() const { return (T*)ptr; }
> };
>
> inline Any myalloc(size_t size) { return Any(malloc(size)); };
>
> double* d=myalloc(100);
> int   * i=myalloc(100);

Well, this is a solution how to avoid building it into the
language; but unless it's at least in the standard library, there's
no advantage in doing so, since it would not improve anything.
Old code won't use myalloc instead of malloc, and new code generally
shouldn't use malloc anyway.

>
> Besides, putting in a reinterpret_cast serves as a reminder that
> we're working with low-level code.  All type conversions should
> be explicit so that we can be careful about what is going on.
>
> double* d=reinterpret_cast<double*>(malloc(100));
> int   * i=reinterpret_cast<int   *>(malloc(100));

Usually you would do a static_cast here (reverse of a standard
conversion). Indeed, I'm not shure if the standard guarantees
that reinterpret_cast gives the desired behaviour (however,
maybe the demand that reinterpret cast shall be "unsurprising"
could be read to do so). OTOH, static_cast is guaranteed to work
here. (Generally it's written as (int*)malloc(100), which is
exactly equivalent to static_cast<int*>(malloc(100)).)

>
> >for functions like malloc, which could be defined as
> >
> >and then could be used in C++ as in C like
> >
> >char* p=malloc(1000);
> >
> >without a cast, but without destroying the safety of void*.
> >any* would be the type that raw memory allocation function should
> >return.
>
> But operator new[] already does this!  First, it calls
>   void* operator new[](...)
> to find space.  Then it casts the resulting space from
> void* to whatever*.  So it is a sort of overloading by
> return type too, but I guess that's ok here.

However, since C has no operator new[], this doesn't help
C compatibility.

The type any could in addition be useful as the following:
Since functions like malloc shall return memory suitably aligned
for everything, the alignment requirement of any would reflect that.
That is, if you allow any to be instantiated, then you'd get
an aligned static buffer quite easily:

union
{
  any alignment_fixer;
  char data[bufsize];
}

If in addition any is demanded as the smallest type possible
to meet those requirements, then you'd get the maximum alignment
simply with sizeof(any).
That is, type any could be useful even beyond C compatibility.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "Jim Cobban" <Jim.Cobban.jcobban@nt.com>
Date: 1998/09/03
Raw View
In article <35EBE2D7.4304B8A9@physik.tu-muenchen.de>,
Christopher Eltschka  <celtschk@physik.tu-muenchen.de> wrote:
>Indeed the main reason for any* is compatibility to C, since in
>C it is quite commmon to do something like
>
>int* p = malloc(20*sizeof(int));
>
>and with malloc returning the new any* type, this would continue
>to work under C++. As a nice side effect it would improve type

It could be that this behavior of malloc under C++ is left not just because
it would be difficult to define in a type safe way, but also to encourage
the use of new.  That is new always returns a pointer of the correct type.

If you do not wish to convert your C code, with lines like the above, into
C++ then compile it as C.  You can still call it from C++.  C++ does not
guarantee to compile all C programs precisely because it is more type safe.
If you have made the decision to compile this code under C++, which includes
changing the file name since if you leave it as .c it will be compiled
according to C rules, then you should replace lines like that with:

 int* p = new int[20];
--
Jim Cobban   |  jcobban@nortel.ca                   |  Phone: (613) 763-8013
Nortel (MCS) |                                      |  FAX:   (613) 763-5199
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: sbnaran@localhost.localdomain (Siemel Naran)
Date: 1998/09/03
Raw View
On 02 Sep 98 03:23:29 GMT, Christopher Eltschka
>> On 28 Aug 1998 16:42:42 GMT, Christopher Eltschka

-----

>> The main problem with this Any* is that it looks a little like
>> overloading by return type.  Kind of like this:
>>    int   * NULL() { return (int   *)0; }
>>    double* NULL() { return (double*)0; }

>I don't see that. Would you see automatic conversion of T* to void*
>as overloading on return type as well, since you can do
>
>int* f();
>
>int* a=f();
>void* b=f();

The conversion from T* to void* is ok because void* is more general
than T*.  IOW, the inheritance hierarchy looks like this
   class int* : public void* { ... };
   class double* : public void* { ... };
At least that's how I like to think of it.

By contrast, the conversion from void* to T*, or T1* to T2*, is not ok.
For this reason, the conversion from any* to T* seems a little type unsafe.

-----

>Indeed the main reason for any* is compatibility to C, since in
>C it is quite commmon to do something like
>
>int* p = malloc(20*sizeof(int));
>
>and with malloc returning the new any* type, this would continue
>to work under C++. As a nice side effect it would improve type
>safety in C++ for NULL, since now NULL could be defined as
>((any*)0), analoguous to the C definition ((void*)0).

Thanks for pointing this out.  I didn't ever learn C.  So you
want your C code to work in C++ without any change?  That is,
with no rewriting.  The best way I can think of to do this in
the existing language is to enhance the pre-processor,

// begin PROGRAM

#if !defined(c_plus_plus)
#define reinterpret_cast<T>(EXPR) (EXPR)
#endif

int* p=reinterpret_cast<int*>(malloc(...));

// end PROGRAM

This compiles on both C and C++ programs.

-----

>> double* d=reinterpret_cast<double*>(malloc(100));
>> int   * i=reinterpret_cast<int   *>(malloc(100));

>Usually you would do a static_cast here (reverse of a standard
>conversion). Indeed, I'm not shure if the standard guarantees
>that reinterpret_cast gives the desired behaviour (however,
>maybe the demand that reinterpret cast shall be "unsurprising"
>could be read to do so). OTOH, static_cast is guaranteed to work
>here. (Generally it's written as (int*)malloc(100), which is
>exactly equivalent to static_cast<int*>(malloc(100)).)

Are you sure?  reinterpret_cast seems fine here.  malloc returns
memory properly aligned for any object.  That is, the numerical
value of the return of malloc is a multiple of the most
stringent (ie. largest) alignment type.  The return is a void*.
So both static_cast and reinterpret_cast should be entirely
equivalent here.  Is this so?


--
----------------------------------
Siemel B. Naran (sbnaran@uiuc.edu)
----------------------------------
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Anatoli <REMOVEanatoli@capsptc.com>
Date: 1998/09/03
Raw View
Siemel Naran wrote:
[snip]
> The conversion from T* to void* is ok because void* is more general
> than T*.  IOW, the inheritance hierarchy looks like this
>    class int* : public void* { ... };
>    class double* : public void* { ... };
> At least that's how I like to think of it.
>
> By contrast, the conversion from void* to T*, or T1* to T2*, is not ok.
> For this reason, the conversion from any* to T* seems a little type unsafe.

Not at all.  Think of any* as less general than any other pointer type
and you're ok.

class any* : public int*, public double*, publuc user_defined_type_1*,
....

This approach is used in Eiffel, though terms are different.
--
Regards
Anatoli (anatoli at ptc dot com) -- opinions aren't


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: James Kuyper <kuyper@wizard.net>
Date: 1998/09/04
Raw View
Siemel Naran wrote:
>
> On 02 Sep 98 03:23:29 GMT, Christopher Eltschka
...
> >> int   * i=reinterpret_cast<int   *>(malloc(100));
>
> >Usually you would do a static_cast here (reverse of a standard
> >conversion). Indeed, I'm not shure if the standard guarantees
> >that reinterpret_cast gives the desired behaviour (however,
> >maybe the demand that reinterpret cast shall be "unsurprising"
> >could be read to do so). OTOH, static_cast is guaranteed to work
> >here. (Generally it's written as (int*)malloc(100), which is
> >exactly equivalent to static_cast<int*>(malloc(100)).)
>
> Are you sure?  reinterpret_cast seems fine here.  malloc returns
> memory properly aligned for any object.  That is, the numerical
> value of the return of malloc is a multiple of the most
> stringent (ie. largest) alignment type.  The return is a void*.
> So both static_cast and reinterpret_cast should be entirely
> equivalent here.  Is this so?

When two different casts are equivalent, you should generally use the
safest one. A C-style cast is the most dangerous one, and
reinterpret_cast<> is the next most dangerous.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1998/08/28
Raw View
What about a new pointer type any*, which is the "opposite" to void*,
in that it can be implicitly converted into any pointer types, but
no pointer type can be implicitly converted to any*. This would be
useful
for functions like malloc, which could be defined as

any* malloc(size_t size);

and then could be used in C++ as in C like

char* p=malloc(1000);

without a cast, but without destroying the safety of void*.
any* would be the type that raw memory allocation function should
return.
In addition, it would allow to make the NULL macro as typesafe as
possible in C (yes, C can be more typesafe here!), by defining
NULL as (any*)0.

Headers to be used in C and C++ could define malloc and NULL like this:

#ifdef __cplusplus
#define _Any any
#else
#define _Any void
#endif

_Any* malloc(size_t size); /* void* for C, any* for C++ */

#define NULL ((_Any*)0); /* (void*)0 for C, (any*)0 for C++ */

Any thoughts about that?


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]