Conversion from int** to const int**

前端 未结 3 1080
逝去的感伤
逝去的感伤 2020-12-10 05:22

Why do I get in this code:

void foo ( const int ** );

int main() {
    int ** v = new int * [10];
    foo(v);

    return 0;
}

this error:

相关标签:
3条回答
  • 2020-12-10 06:00

    it 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 ** is: "a pointer to a pointer to an integer".
    • const int ** is: "a pointer to a pointer to a constant integer".

    The use of const is a contract and you cannot meet this contract by going through the indirection of two references.

    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 it would be possible to modify const char always, just use procedure above.

    And also:

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

    nice cite from the link below:

    By way of analogy, if you hide a criminal under a lawful disguise, he can then exploit the trust given to that disguise. That's bad.

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

    related to this is also invalid conversion Derived** → Base**. If it were legal to convert Derived** → Base**, the Base** could be dereferenced (yielding a Base*), and the Base* could be made to point to an object of a different 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:

    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 
    }
    
    0 讨论(0)
  • 2020-12-10 06:04

    You can only add const qualification in a conversion between similiar pointer types if you add const at all levels from the first difference in cv qualification and up.

    So, you can convert int** to int const* const*, but not to int const* *. If it were allowed to omit adding const at intermediate levels you would be able to 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
    
    0 讨论(0)
  • 2020-12-10 06:22

    You're being misled here by C++'s confusing parsing rules for pointers. It might be clearer to look at this way:

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

    What foo()'s parameter list promises is that you'll be passing it a pointer to a (pointer-to-constant-thing). But new int*[10] means "pointer to (pointer-to-not-constant-thing)".

    So if foo were defined like this:

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

    whereas I think you're expecting that

    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 it's not p that you're declaring to be constant, it's the thing it points to.

    Anyway just use a typedef in this case and everything will be clear and readable.

    0 讨论(0)
提交回复
热议问题