Topic: const correctness question


Author: Anders Pytte <anders@milkweed.com>
Date: 2000/07/26
Raw View
in article 8lk1mq$g4g$1@nnrp1.deja.com, Alan Stokes at
alanstokes@my-deja.com wrote on 7/26/00 2:43 AM:

> What's wrong with the following?
>
> It compiles under MSVC 6, but I feel it shouldn't do. In particular,
> binding a reference to const X * to an X * appears to allow const
> correctness to be violated.
>
> I've looked in section 8.5.3, but I'm not sure I understand it
> correctly. Paragraph 1 appears to allow this, but is paragraph 1
> restricted by the rest of the section or extended by it?
>
> void f(const char * & p)
> {
> static const char a[] = "Hello";
> p = a;
> }
>
> int main()
> {
> char * p;
> f(p);
> *p = 'a';
>
> return 0;
> }

The question should be identical to the following:

int main()
{
    static const char a[] = "Hello";
    char * p;
    char const * & q = p; // ok?
    q = "Hello";
    *p = 'a';

    return 0;
}

This looks okay at first glance and it does not even generate a warning
under Metrowerks C++.

However, I believe this does not conform to the standard. The 8.5.3.4
definition of "reference-compatible" requires that the lhs and rhs types be
the same, or that the lhs be a base class of the rhs. It also requires that
the cv-qualification of the lhs be greater or equal to that of the rhs, but
i believe that point is irrelevant in this case.

If the types are not "reference-compatible" an assignment may still be
performed if the rhs may be implicitly converted to a type that is
"compatible", and the lhs is non-volatile const qualified, in which case a
temporary is constructed.

Given the general case:

cv T2 t2;
cv T1& t1 = t2;

one might suppose the const in the original example is qualifying the
reference type, but it is not. In fact, T2 is type char * and T1 is type
char const *. Thus the types are different and the assignment is ill-formed
(since the reference itself is not const qualified).

Some interesting alternatives would be:

int main()
{
    static const char a[] = "Hello";
    char const * p;
    char const * & q = p;
        // ok because lhs and rhs types are the same

    q = a;      // ok
    *p = 't';   // illegal assignment to constant

    return 0;
}

or

int main()
{
    static const char a[] = "Hello";
    char * p;
    char * & q = p;
        // ok because lhs and rhs types are the same

    q = a;      // illegal implicit const pointer conversion
    *p = 't';   // ok

    return 0;
}

or

    char * p;
    char const * const & q = p;
        // ok because temporary of type char const *
        // can be created and initialized from p
        // and reference is const qualified

    q = a;      // illegal assignment to constant
    *p = 'a';   // ok

In every case const qualification is enforced.

Anders.


--
Anders Pytte                                   Milkweed Software
PO Box 32                                  voice: (802) 586-2545
Craftsbury, VT 05826                  email: anders@milkweed.com

---
[ 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: "Michael Kochetkov" <mkochetk@trustworks.commm>
Date: 2000/07/27
Raw View
[...]
> I've looked in section 8.5.3, but I'm not sure I understand it
> correctly. Paragraph 1 appears to allow this, but is paragraph 1
> restricted by the rest of the section or extended by it?
3.9.3/1 says that cv-qualified or cv-unqualified vertions of a type are
distinct types.
According to 8.5.3/4 const char* and char* are not reference-related (they
are different types) ==> they are not reference-compatible ==> 8.5.3/5 first
otherwise bullet should be applied, i.e. reference parameter of your f
function should be of the type char* const &p (or const char* const &p if
you wish).

With regards,
Michael Kochetkov.

>
> void f(const char * & p)
> {
>    static const char a[] = "Hello";
>    p = a;
> }
>
> int main()
> {
>    char * p;
>    f(p);
>    *p = 'a';
>
>    return 0;
> }
>
>
> --
> - Alan



---
[ 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: wmm@fastdial.net
Date: 2000/07/27
Raw View
In article <8lk1mq$g4g$1@nnrp1.deja.com>,
  Alan Stokes <alanstokes@my-deja.com> wrote:
> What's wrong with the following?
>
> It compiles under MSVC 6, but I feel it shouldn't do. In particular,
> binding a reference to const X * to an X * appears to allow const
> correctness to be violated.
>
> I've looked in section 8.5.3, but I'm not sure I understand it
> correctly. Paragraph 1 appears to allow this, but is paragraph 1
> restricted by the rest of the section or extended by it?
>
> void f(const char * & p)
> {
>    static const char a[] = "Hello";
>    p = a;
> }
>
> int main()
> {
>    char * p;
>    f(p);
>    *p = 'a';
>
>    return 0;
> }

You're right, this should not compile.

The answer in the Standard is found in paragraphs 4-5 of
8.5.3.  Using the terms of those paragraphs, T1 (the
type of the reference) is const char* and T2 (the type
of the initializer) is char* (both cv1 and cv2 are nil).
These two types are not "reference compatible" (which
requires that the types be identical or T1 be a base class
of T2).  Consequently, a temporary will be made to hold
the initializer value and cv1 must be const.  Since cv1
is _not_ const in your example, the program is ill-formed.
(That is, if f's parameter were "const char* const &", you
could pass an argument of type char* to it; then, however,
you wouldn't be able to assign to it inside the body of f
and const-correctness would be preserved.)

With respect to the relationship of paragraph 1 to the rest
of the section, paragraph 1 says only that it is possible
to create _some_ reference when the initializer type is
convertible to the reference type; paragraphs 4-5 describe
_what kind_ of reference can be created (a reference to
const, when the types aren't reference-compatible).

--
William M. Miller, wmm@fastdial.net
Vignette Corporation (www.vignette.com)


Sent via Deja.com http://www.deja.com/
Before you buy.

---
[ 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: Jerry Coffin <jcoffin@taeus.com>
Date: 2000/07/27
Raw View
In article <8lk1mq$g4g$1@nnrp1.deja.com>, alanstokes@my-deja.com
says...
> What's wrong with the following?
>
> It compiles under MSVC 6, but I feel it shouldn't do. In particular,
> binding a reference to const X * to an X * appears to allow const
> correctness to be violated.

That's correct.  If you use the /Za switch to tell VC++ to be as
close to conforming as possible, it'll reject your code with the
following error message:

tst.cpp(10) : error C2664: 'f' : cannot convert parameter 1 from
'char *' to 'const char *& '
        Conversion loses qualifiers

In fairness, it's hard to use this flag since the compiler won't
accept its own headers with it turned on, but in this particular case
you're not using any headers, so you can get the compiler to tell you
about the problem with the code.

--
    Later,
    Jerry.

The universe is a figment of its own imagination.

---
[ 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: hinnant@anti-spam_metrowerks.com (Howard Hinnant)
Date: 2000/07/27
Raw View
In article <B5A37D88.8107%anders@milkweed.com>, Anders Pytte
<anders@milkweed.com> wrote:

| The question should be identical to the following:
|
| int main()
| {
|     static const char a[] = "Hello";
|     char * p;
|     char const * & q = p; // ok?
|     q = "Hello";
|     *p = 'a';
|
|     return 0;
| }
|
| This looks okay at first glance and it does not even generate a warning
| under Metrowerks C++.
|
| However, I believe this does not conform to the standard.

This will be fixed in our next release.

Error   : non-const '&' reference initialized to temporary
HelloWorld.cp line 5   char const * & q = p; // ok?

-Howard

---
[ 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: Alan Stokes <alanstokes@my-deja.com>
Date: 2000/07/26
Raw View
What's wrong with the following?

It compiles under MSVC 6, but I feel it shouldn't do. In particular,
binding a reference to const X * to an X * appears to allow const
correctness to be violated.

I've looked in section 8.5.3, but I'm not sure I understand it
correctly. Paragraph 1 appears to allow this, but is paragraph 1
restricted by the rest of the section or extended by it?

void f(const char * & p)
{
   static const char a[] = "Hello";
   p = a;
}

int main()
{
   char * p;
   f(p);
   *p = 'a';

   return 0;
}


--
- Alan


Sent via Deja.com http://www.deja.com/
Before you buy.

---
[ 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              ]