Re: Variables in for loop (style issue)
vandevoorde@gmail.com wrote:
Walter Bright wrote:
vandevoorde@gmail.com wrote:
I'm not sure why you bring that example up: It's unrelated to the
one you mentioned earlier and which I was commenting on.
In this latter example, the const is not top level, and hence it is
indeed not useful to an optimizer.
I'm sorry, I misunderstood you. I infer you're talking about:
void foo(const int& end) { ... }
...
for (int i = 0; i < end; i++)
{
foo(end);
}
Note that in your original example the "end" referred to in the
"for" statement was declared
const size_t end = ...;
The Standard 5.2.2-5:
"[Note: a function can change the values of its nonconst
parameters, but these changes cannot affect the values
of the arguments except where a parameter is of a reference type
(8.3.2); if the reference is to a constqualified
type, const_cast is required to be used to cast away the constness in
order to modify the
argument's value. Where a parameter is of const reference type a
temporary object is introduced if
needed (7.1.5, 2.13, 2.13.4, 8.3.4, 12.2). In addition, it is possible
to modify the values of nonconstant
objects through pointer parameters. ]"
I read that as foo() may modify 'end' by using a const_cast, and
therefore the optimizer must assume that it might.
Not in this case: If the referenced object has a const-qualified type,
trying to modify it by casting away constness is undefined behavior
(see 7.1.5.1/4, and the related note in 5.2.11/7).
Let me clarify the two cases here:
1) This is legal, standard conforming code:
void foo(const int& end)
{ int* p = &const_cast<int&>(end);
*p = 3; // modify x
}
int x;
foo(x);
2) This is undefined behavior:
void foo(const int& end)
{ int* p = &const_cast<int&>(end);
*p = 3; // modify const x
}
const int x;
foo(x);
The only difference is whether x is const or not, not whether foo()
takes a reference to const. So we are back to const as type modifier
having no useful meaning to an optimizer.
Const as storage class, however, is treated very differently, i.e. it
can actually assumed to be constant (and so can be used in "constant
propagation" compiler optimizations).
In my statements about the (lack of) utility of const, I am talking
about type modifier const, not storage class const. D does have storage
class const.
Back to the loop example, given:
void foo(const int& end)
{ int* p = &const_cast<int&>(end);
*p = 3; // modify const x
}
const int end = ...;
for (int i = 0; i < end; i++)
{
foo(end);
}
Yes, I agree with you here that the addition of const (as storage class)
to 'end' means that the optimizer can assume that 'end' is loop
invariant, even though foo() attempts to modify it. And yes, my
optimizer will treat top level storage class const as being constant,
regardless of whether a pointer or reference to it is taken or not.
Where the optimizer ignores const is when const is used as a type
modifier. For the loop case, the fact that foo takes a reference to
const is of no value to the optimizer. The only thing of value is if
'end' itself is storage class const or not.
I think we've been misunderstanding each other, and I hope this clears
it up.
It's technically only one meaning (with two grammatical locations,
although both location can be useful for optimization purposes):
A type qualifier. From an optimization perspective, it's only useful
when appearing at the top level of a variable type. (That's probably
what you mean by the "storage class meaning", but the language
is consistent in treating is as a type qualifier.)
The Standard does treat the two cases differently, for example, see
7.1.5.1-2:
"A variable of const qualified integral or enumeration type initialized
by an integral
constant expression can be used in integral constant expressions (5.19)."
It treats various cases of constness in special ways, but its always
in terms of the type system. You mention one special case,
It's not just a special case, it is a crucial distinction from which
follows that const as a storage class means that the data can actually
be assumed to be constant by the compiler. Any other use of const cannot
assume this. While I agree that the standard refers to the storage class
const in terms of the type system, it's behavior is that of a storage
class, not a type. The two behaviors are fundamentally different, and
are at the root of the special cases listed in the standard.
and
another one is the notion that rvalue can bind to reference-to-const
types.
-Walter Bright
www.digitalmars.com C, C++, D programming language compilers
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]