Re: Const trouble
* Johannes Bauer:
Alf P. Steinbach schrieb:
* Johannes Bauer:
Hello group,
I've run into some *very* nasty trouble which I could (after hours of
work) trace to a problem in my use of the const keyword (which
appearently has not been appropriate). It is very difficult to trace, as
it only appears when the program is compiled with g++ and -O3 (-O2 and
below work fine).
So I'm guessing it's some kind of aliasing issue.
One of my classes provides an operator*=, which takes a const Fred& as a
parameter. As soon as I remove the const, it also works with -O3.
Reproduce in small program, post complete code.
Since this is not possible
I have chosen to just ask my questions in
order to find the problem myself. The code is around 20 kLOC total
containing at least 6 libraries which are dynamically loaded at runtime.
If I *could* reproduce the problem chances are I could also fix it.
Now since it is very difficult to trace remotely, I have some general
questions about usage of const:
1. Is it always safe to do a c-style cast in which const is *added*?
No, it's not always safe to add const.
See the FAQ.
I've read the FAQ section about const correctness (actually: in advance
to posting here) - I did not find this in there, though. I did not find
"const" methods in there either.
E.g. look at
http://www.parashift.com/c++-faq-lite/const-correctness.html#faq-18.17
And you should avoid C style casts.
What is the difference between a reinterpret_cast and a C-style cast?
A C style cast can perform various kinds casts, a reinterpret_cast only performs
a reinterpret_cast.
I.e. I have a method which can access a foo* r/w - can it also return
(const foo*)x?
Sorry, that's a meaningless question: the two things are not related.
Sigh.
Yes.
2. Is there a difference between const_cast and a c-style cast which
modifies only the const keyword?
Yes.
You have no guarantee what the C style cast does.
The C style cast yields UB?
Casting often yields UB.
And perhaps that's your problem, that you have introduced as
reinterpret_cast where you thought you were just adding const. Wouldn't
surprise me. Remove all C casts in your code.
There were indeed a few instances where that was the case. I removed
them, the problem stayed.
How can you be sure you removed them when you're using C style casts.
You can't.
Remove the C style casts.
3. In a class like this:
class foo {
private:
int *x;
public:
void blah() const {
x[9] = 123;
}
};
Is it safe to declare blah() const?
That depends on whether 'x' points to per-instance data or not.
Can you elaborate? Suppose there are two different scenarios:
class foo1 {
private:
int *x;
public:
foo() {
x = new int[128];
}
void blah() const {
x[9] = 123;
}
};
class foo2 {
private:
int *x;
public:
foo() {
x = singelton::get();
}
void blah() const {
x[9] = 123;
}
};
Never mind the lost memory in foo1 and suppose the static singleton::get
returns a pointer to global memory which will never change.
In that case the constness of foo2::blah is technically correct.
The correctness of the constness of foo1::blah depends on whether x represents
per-instance data or not.
If it does, that is, if the x in foo1 can be replaced with a std::vector<int>,
then the constness of foo1::blah is incorrect, as the compiler will *tell* you
if do change over to std::vector<int>.
It's unclear since you have chosen to express the code at the lowest
possible level of abstraction
Yes, because that is where it becomes difficult.
It only becomes "difficult" because you're actively removing every clue about
what you're actually trying to do. Unless you want the "difficulty" that's just
stupid. Stop removing information about what you're trying to express, and
voil?, no more "difficulties" -- or at least, greatly reduced frequency.
It's exactly constructs
as above that I want to know about, hence my question. This was
deliberately done so.
Huh.
Cheers & hth.,
- Alf