Topic: Q: 'const T*' for non-lvalue T


Author: Oleg Zabluda <zabluda@math.psu.edu>
Date: 1997/04/18
Raw View

James Kanze <james-albert.kanze@vx.cit.alcatel.fr> wrote:
: There are at least
: two other cases, however, where I still use C style arrays:
: 1. For small class member arrays ....
: 2. For statically initialized const arrays....

3. For user-defined memory management routines.

4. For union-style tricks.

Oleg.
--
Life is a sexually transmitted, 100% lethal disease.
---
[ 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         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1997/04/15
Raw View
Jess Holle <jessholl@netcom.com> writes:

> I understand and value the use of const for arguments of type 'T&' and
> 'T*' where T is a non-lvalue type.
>
> I had thought that the application of 'const' in cases where T is an
> lvalue was just as simple and was consistent with that for non-lvalue
> types T.

A type isn't a lvalue or a rvalue. I don't understand what you mean.

Perhaps you mean array/non-array type ? const apply correcly
to arrays be normal arrays don't convert correctly to
const ones.

> Some compilers (e.g. MSVC++ 4.2), however, disagree with code
> that I write based upon this assumption.  Others (e.g. Metrowerks CW 11)
> give no errors or warnings to my code.

CW has always be broken wrt constness.
(But in this case it has a more intelligent behaviour.)

> The language of the standard sheds
> no light on the issue for me.
>
> This leaves me with a few questions/problems:
>   1)  Which set of compilers is actually right and what is the logic to
>       follow when using 'const T&' and 'const T*' for non-lvalue T?

'T*' is convertible to 'const T*' and a 'const T&' can be built
with a rvalue (a temporary).

>   2)  If my code is wrong, then how should my sample code be rewritten to
>       be 'const' safe and ANSI compliant?

Use const_cast or remove const from both SomeVector::elements
and ProcessPoints.

>   3)  Is it possible to achieve 'const' correctness/safety for pointers
>       and references to non-lvalue types T in a way which is portable
>       across most compilers today?

Yes, MSVC++ is correct in this case; g++ seems rather well-behaved
wrt const-correctness.

> My code sample follows.  It is based on my understanding of 'const' - that
> proper 'const' specifications on function arguments should _never_
> inconvenience those writing client code, but rather _allow_ (not require)
> them to obtain better compiler error checking through appropriate usage of
> const in their own code.  This understanding is contradicted by the
> compiler error marked below.

Yes, the std is broken.

>    template <class T>
>    class  SomeVector  // simplification of expandable array class
>    {
>     public:
>      SomeVector() : m_array( 0 )  {}
>      const T  *elements() const  { return ( m_array ); }
>        // I did get a compiler error HERE before simplifying this class!
>     private:
>      T  *m_array;
>    };
>
>    void  ProcessPoints( int n, const float (*points)[3] );
>
>    int  main()
>    {
>      SomeVector<float[3]>  Pts;
>      float                 pts[10][3];  // assignment omitted
>      ProcessPoints( 0, Pts.elements() );
>      ProcessPoints( 10, pts );
>        // MSVC++ error on this last line unless I remove 'const'
>        // from ProcessPoints() prototype, in which case I get an
>        // error on the previous line!!!

Strangely, T(*)[n] isn't convertible to const T(*)[n]; don't
ask me why, I don't think there is any reason.

pts is float[10][3] and won't convert to float(*)[3].

James Kanze advice: don't use built-in arrays

--

Valentin Bonnard
mailto:bonnardv@pratique.fr
http://www.pratique.fr/~bonnardv (Informations sur le C++ en Francais)
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: jessholl@netcom.com (Jess Holle)
Date: 1997/04/16
Raw View
First, let me thank you for the first meaningful response I've seen on
this subject.

>A type isn't a lvalue or a rvalue. I don't understand what you mean.

What I mean, but appear not to be stating correctly, is a reference or
pointer type.  In other words, a type which can serve as an lvalue.

>Perhaps you mean array/non-array type ? const apply correcly
>to arrays be normal arrays don't convert correctly to
>const ones.

?

>CW has always be broken wrt constness.
>(But in this case it has a more intelligent behaviour.)

As far as I've seen if the ANSI C++ standard followed CW in this regard
we'd be better off.  I haven't seen a case where I preferred another
compiler's handling of 'const' to CW's.

>> This leaves me with a few questions/problems:
>>   1)  Which set of compilers is actually right and what is the logic to
>>       follow when using 'const T&' and 'const T*' for non-lvalue T?
>
>'T*' is convertible to 'const T*' and a 'const T&' can be built
>with a rvalue (a temporary).

This was my understanding but it appears to fall apart when T is an array
type and as I recall when T is itself a pointer type, but I haven't
verified that recently.

>>   2)  If my code is wrong, then how should my sample code be rewritten to
>>       be 'const' safe and ANSI compliant?
>
>Use const_cast or remove const from both SomeVector::elements
>and ProcessPoints.

That is what I've done (first used const_cast<>, then got sick of the
whole business and removed 'const's), but I consider this a hack - castes
should only be necessary when you are overriding the "natural" type
meanings - I'm not in my example IMHO.  From examples such as this,
'const' appears to me to be a useless and untenable concept for array
types.


>Yes, the std is broken.

I agree 200% and would _really_ like to see something done about it before
it goes final!

>pts is float[10][3] and won't convert to float(*)[3].

Every compiler that I've tried accepts this conversion and I'm convinced
it is a correct, trivial conversion.  The other conversion (the one with
'const' added in the latter case) is not accepted and this is what
disturbs me.

>James Kanze advice: don't use built-in arrays

It is highly obnoxious not to when dealing with low-level (sometime C) code.

--
---------------------------------------------------------------------
Jess Holle and /                                   jessholl@netcom.com
Wendy Vidlak  /
Norwood, MA  /  ftp://ftp.netcom.com/pub/je/jessholl/j_and_w_www.html
---
[ 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         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: James Kanze <james-albert.kanze@vx.cit.alcatel.fr>
Date: 1997/04/17
Raw View

jessholl@netcom.com (Jess Holle) writes:

|>  That is what I've done (first used const_cast<>, then got sick of the
|>  whole business and removed 'const's), but I consider this a hack - castes
|>  should only be necessary when you are overriding the "natural" type
|>  meanings - I'm not in my example IMHO.  From examples such as this,
|>  'const' appears to me to be a useless and untenable concept for array
|>  types.

Not really.  It's only when arrays start getting converted implicitly to
pointers that it causes problems, and even then, I think it is open to
interpretation (and that the preferred interpretation would be to make
it work.

|>  >Yes, the std is broken.
|>
|>  I agree 200% and would _really_ like to see something done about it before
|>  it goes final!

The standard is broken, in a very large sense, with regards to arrays.
This is known; even well known.  It is also known that any fix would
break 99% of all existing programs.  So we live with it.  (In the case
of C++, it is less of a problem, because we do have alternatives.)

|>  >pts is float[10][3] and won't convert to float(*)[3].
|>
|>  Every compiler that I've tried accepts this conversion and I'm convinced
|>  it is a correct, trivial conversion.  The other conversion (the one with
|>  'const' added in the latter case) is not accepted and this is what
|>  disturbs me.

I think it is open to interpretation.  As I think I pointed out in
another posting, whether this is legal or not depends on when the
conversion array->pointer takes place with regards to the shifting of
the const from the array to the individual elements.

I've forgotten the original example, but the following code works with
both Cfront and g++:

 typedef int X[5][3] ;

 void
 f( const X ) {}

 void
 g( const X& ) {}

 void
 h( const X* ) {}

 int
 main()
 {
  X   x ;
  f( x ) ;
  g( x ) ;
  h( &x ) ;
  return 0 ;
 }

|>  >James Kanze advice: don't use built-in arrays
|>
|>  It is highly obnoxious not to when dealing with low-level (sometime C) code.

I'm not sure that it is "obnoxious", but such advice is certainly meant
as a general rule, and not an absolute.  Obviously, if you are
interfacing to C, you don't really have a choice.  There are at least
two other cases, however, where I still use C style arrays:

1. For small class member arrays (things like a point in a 3
dimensions).  These is relatively rare, however, in my code, and even
then, I will often use a very simple array class.  (I do agree that
vector is a bit overweight for this, especially if there are going to be
thousands of instances.)

2. For statically initialized const arrays.  At present, the
alternatives aren't as flexible with regards to initialization.  Here
too, however, I will often use a wrapper class (especially as bounds
checking is often relevant).

--
James Kanze      home:     kanze@gabi-soft.fr        +33 (0)1 39 55 85 62
                 office:   kanze@vx.cit.alcatel.fr   +33 (0)1 69 63 14 54
GABI Software, Sarl., 22 rue Jacques-Lemercier, F-78000 Versailles France
     -- Conseils en informatique industrielle --
---
[ 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         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: jessholl@netcom.com (Jess Holle)
Date: 1997/04/13
Raw View

I understand and value the use of const for arguments of type 'T&' and
'T*' where T is a non-lvalue type.

I had thought that the application of 'const' in cases where T is an
lvalue was just as simple and was consistent with that for non-lvalue
types T.  Some compilers (e.g. MSVC++ 4.2), however, disagree with code
that I write based upon this assumption.  Others (e.g. Metrowerks CW 11)
give no errors or warnings to my code.  The language of the standard sheds
no light on the issue for me.

This leaves me with a few questions/problems:
  1)  Which set of compilers is actually right and what is the logic to
      follow when using 'const T&' and 'const T*' for non-lvalue T?
  2)  If my code is wrong, then how should my sample code be rewritten to
      be 'const' safe and ANSI compliant?
  3)  Is it possible to achieve 'const' correctness/safety for pointers
      and references to non-lvalue types T in a way which is portable
      across most compilers today?

My code sample follows.  It is based on my understanding of 'const' - that
proper 'const' specifications on function arguments should _never_
inconvenience those writing client code, but rather _allow_ (not require)
them to obtain better compiler error checking through appropriate usage of
const in their own code.  This understanding is contradicted by the
compiler error marked below.

   template <class T>
   class  SomeVector  // simplification of expandable array class
   {
    public:
     SomeVector() : m_array( 0 )  {}
     const T  *elements() const  { return ( m_array ); }
       // I did get a compiler error HERE before simplifying this class!
    private:
     T  *m_array;
   };

   void  ProcessPoints( int n, const float (*points)[3] );

   int  main()
   {
     SomeVector<float[3]>  Pts;
     float                 pts[10][3];  // assignment omitted
     ProcessPoints( 0, Pts.elements() );
     ProcessPoints( 10, pts );
       // MSVC++ error on this last line unless I remove 'const'
       // from ProcessPoints() prototype, in which case I get an
       // error on the previous line!!!
     return ( 0 );
   }

Any clarification of this issue would be much appreciated.

--
---------------------------------------------------------------------
Jess Holle and /                                   jessholl@netcom.com
Wendy Vidlak  /
Norwood, MA  /  ftp://ftp.netcom.com/pub/je/jessholl/j_and_w_www.html
---
[ 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         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]