Re: On const and the lack thereof
On Jul 7, 1:38 pm, "Francesco S. Carta" <entul...@gmail.com> wrote:
Daniel <danielapar...@gmail.com>, on 06/07/2010 14:53:09, wrote:
<snip>
I tried declaring x and data with mutable. That worked for
data. But when I tried declaring x as
mutable double* x;
it compiled, but resulted in a runtime "write to protected
memory" error inside costFunction. I then tried
double* mutable x;
which worked, but why that and not the other?
As it seems from other replies, this is likely a compiler
specific problem, because those two declaration should be
interpreted as having the same exact meaning.
It's more likely that he changed something else in his code at
the same time. I made a quick trial with VS 2005, and there was
no difference between the two in the generated code.
Besides, I tried something similar somewhere else, read below
the following code please:
//-------
struct Test {
int datum;
mutable int mutable_datum;
Allows changing the int even through a const lvalue expression.
int* ptr;
mutable int* mutable_ptr;
Allows changing the pointer even through a const lvalue
expression.
Test() :
datum(42),
mutable_datum(42),
ptr(&mutable_datum),
mutable_ptr(&datum) {}
};
int main() {
const Test t;
// directly modify data
// fails, OK
// t.datum = 10;
// works, OK
t.mutable_datum = 10;
// indirectly modify data:
// works, OK
*t.ptr = 10;
// works, NOT OK?
*t.mutable_ptr = 10;
This is undefined behavior. In practice: if the object doesn't
have static lifetime (your object has auto lifetime), has
a non-trivial constructor or destructor (your object has
a non-trivial constructor), has any mutable members, or any of
the initializers are not constant expressions, the code will
"work". If you wrote something like:
struct Toto
{
int a;
int* p;
};
Toto const t = { 42, &t.a };
at namespace scope, and tried:
*t.p = 10;
you would likely get a runtime error with some compilers.
Not a compile time error. The compiler is not required to do
the necessary analysis. And the restrictions which result in
a runtime error correspond to the restrictions necessary in
practice for the compiler to place the object in read-only
memory. Modern systems don't have any provision for changing
the protection of a very small block of memory dynamically.
The object cannot be write protected during construction or
destruction, and of course, dynamically allocated memory or
memory on the stack must come from a non-write-protected pool
(and write protecting an object with a mutable member would have
to somehow ensure that the mutable member wasn't
write-protected).
Note too that this is why I would hesitate with statements along
the lines of "a const function may not modify non-mutable
members". In this case, a const member function could still do
++*mutable_ptr, effectively modifying a non-mutable member.
// modify pointers:
// fails, OK
// t.ptr = &t.datum;
// works, OK
t.mutable_ptr = &t.mutable_datum;
return 0;}
//-------
"fails" stands for "does not compile", "works" stands for
"compiles and runs with no runtime error" - I tested it with
MinGW 4.4.0.
The line that reads "NOT OK?" seems like it is casting away
the const that should be attached to "data" - I have no idea
if the standard mandates, allows, forbids or simply doesn't
tell anything about cases like this.
Mutable and const are largely compile time concepts, and (as far
as the compiler is concerned) only affect the basic object.
There's no "casting away" of const; the pointer was initialized
before const took effect.
Could you make some test on your compiler modifying my code
and check whether you get the same error you got on your code?
I'd be very surprised if any compiler behaves differently than
what you've observed.
--
James Kanze