从char * *变量赋值给char * const *变量 - 为什么允许它?

时间:2015-10-14 15:48:06

标签: c++ visual-c++

我对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 ++,如果是的话,理由是什么?这似乎不一致。谢谢!

3 个答案:

答案 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!

当你阅读解释时,有点令人困惑,但要花时间思考一下。这种方式在逻辑上是一致的。