Why can't it convert double ***
to const double ***
?
void foo(const double ***d)
{
}
int main (int args, char*[] args)
{
double ***d;
/*initialize d */
foo(d);
}
Why can't it convert double ***
to const double ***
?
void foo(const double ***d)
{
}
int main (int args, char*[] args)
{
double ***d;
/*initialize d */
foo(d);
}
If your C tag is to be believed, gcc generates a warning as the types differ for both your example and const double * const * const * d
. In C++, it's an error in the OP code but the slap-const-everywhere approach is legal.
The reason the compiler warns you is that a pointer to a pointer ( or further indirection ) allows a pointer to be returned to the caller by modifying the location the parameter points to.
If the target of the pointer is declared as const, then the called function would expect the value it puts there to be treated as const on return.
A simpler case of passing a T**
to a const T**
which illustrates why this is an error would be:
void foo ( const char ** z )
{
*z = "A";
}
int main (int nargs, char** argv)
{
char* z = 0;
char** d = &z;
// warning in C, error in C++
foo ( d );
// bad - modifies const data
z[0] = 'Q';
}
const
in C means that the data won't change. const
in C++ means the data won't change publicly - mutable data in a C++ object can change. A C compiler could optimise its code so that it caches some of the const
data somewhere, but a C++ compiler can't do that due to possible mutablity, so has the weaker restriction that you can't return const data to non-const as above. So in C++, double***
can be cast to const double * const * const * d
as the extra const
s prevent return of non-modifiable memory, but in C it generates a warning and possible errors if the compiler optimises repeated accesses to the memory elsewhere.
This is also true for ** (a pointer to pointer) for identical reasons.
This code also produces this error, and it's clearer to see why the compiler won't let you do this here:
double d = 0.0;
double * pd = &d;
const double ** ppd = &pd; // <--- Error
If you were able to do this, you could have a 'const' pointer to data (ppd), that you could change by changing the mutable value d. This violates const, so the compiler won't let you do this.
Consider d
a pointer to a blackbox.
The compiler can add const to either d
itself or the blackbox, but not the contents of the blackbox. So
void foo1(double ***d); /* ok, no casts needed */
void foo2(double *** const d); /* ok, no casts needed; const added to `d` itself */
void foo3(double ** const *d); /* ok, no casts needed; const added to the blackbox */
void foo4(double * const **d); /* oops, trying to change the insides of the blackbox */
void foo5(const double ***d); /* oops, trying to change the insides of the blackbox */
void foo6(double ** const * const d);
/* ok: d is a constant pointer to a constant blackbox */
The answer to your question can be found at http://www.parashift.com/c++-faq-lite/const-correctness.html#faq-18.17
This means you should really use const double * const * const * d
.