Convert from int ** to const int **

Why am I getting in this code:

void foo ( const int ** ); int main() { int ** v = new int * [10]; foo(v); return 0; } 

this error:

 invalid conversion from 'int**' to 'const int**' [-fpermissive]| 

I thought that one could convert from non-const to const.

+6
source share
3 answers

this is because you are trying to convert from int** to const int**

 int ** v = new int * [10]; // v is int** foo(v); //but foo takes const int** 
  • int ** : "pointer to a pointer to an integer".
  • const int ** : "pointer to a pointer to a constant integer".

Using const is a contract, and you cannot execute this contract by clicking on the link to two links.

From the standard:

 const char c = 'c'; char* pc; const char** pcc = &pc; // not allowed (thankfully!) ^^^ here the bundit is hidden under const: "I will not modify" *pcc = &c; // *pcc is "pointer to const" right? so this is allowed... *pc = 'C'; // would allow to modify a const object, *pc is char right? 

so one could change const char always , just use the procedure above.

And:

 char *s1 = 0; const char *s2 = s1; // OK... char *a[MAX]; // aka char ** const char * const*ps = a; // no error! 

nice cite at the link below:

Similarly, if you hide a criminal under a legitimate disguise, he can then use the trust given to that disguise. This is bad.

http://www.parashift.com/c++-faq-lite/constptrptr-conversion.html

related to this is also an invalid Derived** → Base** conversion. If it would be legal to convert Derived** → Base** , Base** could be dereferenced (by receiving Base* ), and Base * could be pointed to an object of another derived class, which could cause serious problems. See why:

 class Vehicle { public: virtual ~Vehicle() { } virtual void startEngine() = 0; }; class Car : public Vehicle { public: virtual void startEngine(); virtual void openGasCap(); }; class NuclearSubmarine : public Vehicle { public: virtual void startEngine(); virtual void fireNuclearMissle(); }; int main() { Car car; Car* carPtr = &car; Car** carPtrPtr = &carPtr; Vehicle** vehiclePtrPtr = carPtrPtr; // This is an error in C++ NuclearSubmarine sub; NuclearSubmarine* subPtr = ⊂ *vehiclePtrPtr = subPtr; // This last line would have caused carPtr to point to sub ! carPtr->openGasCap(); // This might call fireNuclearMissle()! ... } 

http://www.parashift.com/c++-faq-lite/derivedptrptr-to-baseptrptr.html

consider the following issues:

 class Vehicle { public: virtual ~Vehicle() { } virtual void startEngine() = 0; }; class Car : public Vehicle { public: virtual void startEngine(){printf("Car engine brummm\n");} virtual void openGasCap(){printf("Car: open gas cap\n");} virtual void openGasCap2(){printf("Car: open gas cap2\n");} virtual void openGasCap3(){printf("Car: open gas cap3\n");} virtual void openGasCap4(){printf("Car: open gas cap4\n");} }; class NuclearSubmarine : public Vehicle { public: int i; virtual void startEngine(){printf("Nuclear submarine engine brummm\n");} virtual void fireNuclearMissle3(){printf("Nuclear submarine: fire the missle3!\n");} virtual void fireNuclearMissle(){printf("Nuclear submarine: fire the missle!\n");} virtual void fireNuclearMissle2(){printf("Nuclear submarine: fire the missle2!\n");} }; int main(){ Car car; Car* carPtr = &car; Car** carPtrPtr = &carPtr; //Vehicle** vehiclePtrPtr = carPtrPtr; // This is an error in C++, But: Vehicle** vehiclePtrPtr = reinterpret_cast<Vehicle**>(carPtrPtr); NuclearSubmarine sub; NuclearSubmarine* subPtr = &sub; *vehiclePtrPtr = subPtr; // carPtr points to sub ! carPtr->openGasCap(); // Nuclear submarine: fire the missle3! carPtr->openGasCap2(); // Nuclear submarine: fire the missle! carPtr->openGasCap3(); // Nuclear submarine: fire the missle2! //carPtr->openGasCap4(); // SEG FAULT } 
+14
source

You can only add const qualification to the conversion between similar types of pointers, if you add const at all levels from the first qualification difference cv and up.

So you can convert int** to int const* const* , but not to int const* * . If you were allowed to skip adding const at intermediate levels, you could do something like:

 const int c = 29; int *pi; const int** ppci = &pi; // only adding const, right *ppci = &c; *pi = 0; // changing c ?! but no const_cast in sight 
+5
source

This is where C ++ confuses you by mixing rules for parsing pointers. Perhaps it would be more clear:

 typedef const int * ptr_to_const_int; void foo( ptr_to_const_int *); int main() { int ** v = new int * [10]; foo(v); return 0; } 

Which list of foo () promises parameters is that you pass it a pointer to (a pointer to a constant). But the new int * [10] means "pointer to (pointer-to-not-constant-thing)".

So, if foo were defined as follows:

 foo( const int **p ) { (*p); //<-- this is actually of type const int * } 

then as i think you expect

 foo( const int **p ) { (*p); //<-- you're expecting this to be of type int * p = 0; //<-- and this to throw a compiler error because p is const } 

but this is not the p you declare constant, this is what it points to.

Anyway, just use typedef in this case, and everything will be clear and understandable.

+2
source

Source: https://habr.com/ru/post/944330/


All Articles