我对C ++(Visual Studio 2012编译器)的以下行为感到惊讶。
char * * PointerToPointerToChar = NULL;
char * const * PointerToConstPointerToChar = NULL;
char const * * PointerToPointerToConstChar = NULL;
PointerToPointerToConstChar = PointerToPointerToChar; // Assignment 1: Gives compiler error as I would expect
PointerToConstPointerToChar = PointerToPointerToChar; // Assignment 2: NO COMPILER ERROR ???
PointerToPointerToChar = PointerToPointerToConstChar; // Assignment 3: Gives compiler error as I would expect
PointerToPointerToChar = PointerToConstPointerToChar; // Assignment 4: Gives compiler error as I would expect
我理解C ++中的const关键字,特别是它的位置如何影响被认为是const的东西(左边的实体)。
似乎编译器试图在任何一个间接层(赋值3和4)中保护RHS变量的用户免受const-stripping别名的影响。但是LHS仅在一个间接层(赋值1)而不是另一个间接层(赋值2)中受到const-stripping别名的保护。换句话说,鉴于编译器阻止了以下内容
PointerToPointerToConstChar = PointerToPointerToChar; // Assignment 1: Gives compiler error as I would expect
PointerToPointerToChar[0][0] = 'A'; // The user of the LHS variable was effectively lied to about the constness of the *characters* - second level of indirection
那么为什么编译器也没有阻止以下内容
PointerToConstPointerToChar = PointerToPointerToChar; // Assignment 2: NO COMPILER ERROR ???
PointerToPointerToChar[0] = NULL; // The user of the LHS variable was effectively lied to about the constness of the *pointers* - first level of indirection
这是正确的C ++,如果是的话,理由是什么?这似乎不一致。谢谢!
答案 0 :(得分:3)
type const*
并不意味着该值不会改变,这意味着您无法使用该指针进行更改。
因为如果你可以这样做,你可以分配给*PointerToPointerToConstChar
任何const char*
- 而PointerToPointerToChar
依赖于它是正常的char*
。如果允许的话:
PointerToPointerToConstChar = PointerToPointerToChar; // assume PointerToPointerToChar is pointing to a valid memory block
const char str[] = "Hello world!";
*PointerToPointerToConstChar = str;
(*PointerToPointerToChar)[0] = 'X'; // Oops, we just modified a const array
答案 1 :(得分:1)
将char**
分配给char* const*
类似于将char*
分配给const char*
。这很有道理。
char array[] = "foo";
char* ptr1 = array; // Can change array through ptr1
char const* ptr2 = ptr1; // Can't change array through ptr2
char**
和char* const*
的使用使得可以和不可更改的内容复杂化。
char** ptrptr1 = &ptr1;
// Can change where ptr1 points to through ptrptr1
*ptrptr1 = <some other char*>; // OK
// Can change the value of what ptr1 points to through ptrptr1.
(*ptrptr1)[0] = 'x'; // OK
char* const* ptrptr2 = ptr1;
// Can't change where ptr1 points to through ptrptr2
*ptrptr2 = <some other char*>; // Not OK
// Can change the value of what ptr1 points to through ptrptr2.
// (*ptrptr2) is still of type 'char*'.
(*ptrptr2)[0] = 'x'; // OK
答案 2 :(得分:1)
你有一个const
的指针。指针不是const
,而是指向它。您为该指针指定了一个指向非const
的指针。那样就好。指针不是const,在这种情况下const
告诉我们,指向的对象不会通过此指针更改。它不必是其他任何地方的常数。
char* c = someCharPointerSomewhere;
PointerToConstPointerToChar = PointerToPointerToChar;
*PointerToConstPointerToChar = c // const violation
*PointerToPointerToChar = c // this is fine
// now *PointerToConstPointerToChar will be c as well.
那为什么不能指向指向const
的指针?好吧,指向const
的指针与指向非const
的指针不同。我们上面的隐式转换在这种情况下不适用。你可以使用这个指针让它指向的指针指向某个东西,实际上是const
。然后原始指针允许间接修改const值。
const char c = 'c';
PointerToPointerToConstChar = PointerToPointerToChar;
*PointerToPointerToConstChar = c;
**PointerToPointerToChar = 'a'; // const violation!
当你阅读解释时,有点令人困惑,但要花时间思考一下。这种方式在逻辑上是一致的。