为什么将“指向非const的指针”转换为“指向const的指针”是不合法的

时间:2010-02-08 10:33:52

标签: c++ pointers const const-correctness

将指针转换为指向const的指针是合法的。

那么为什么将指向非const 的指针转换为指向const 指针的指针是不合法的呢?

例如,为什么以下代码是非法的:

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

5 个答案:

答案 0 :(得分:35)

来自标准:

const char c = 'c';
char* pc;
const char** pcc = &pc;   // not allowed
*pcc = &c;
*pc = 'C';                // would allow to modify a const object

答案 1 :(得分:18)

忽略您的代码并回答您的问题原则,请参阅comp.lang.c常见问题中的此条目: Why can't I pass a char ** to a function which expects a const char **?

  

您无法将char **值分配给const char **指针的原因有点模糊。鉴于const限定符完全存在,编译器希望帮助您保证不修改const值。这就是为什么你可以将char *分配给const char *,而不是相反:将const添加到一个简单的指针显然是安全的,但它会很危险拿走它。但是,假设您执行了以下更复杂的分配系列:

const char c = 'x';    /* 1 */
char *p1;              /* 2 */
const char **p2 = &p1; /* 3 */
*p2 = &c;              /* 4 */
*p1 = 'X';             /* 5 */
     

在第3行中,我们将char **分配给const char **。 (编译器应该抱怨。)在第4行中,我们将const char *分配给const char *;这显然是合法的。在第5行中,我们修改char *指向的内容 - 这应该是合法的。但是,p1最终指向c,即const。这是第4行,因为*p2确实是p1。这是在第3行中设置的,这是一个不允许的表单的赋值,这正是为什么不允许第3行的原因。

由于你的问题被标记为C ++而不是C,它甚至解释了要使用的const限定符:

  

(C ++有更复杂的规则来分配const限定指针,这些指针可以让你在不引发警告的情况下进行更多种类的赋值,但仍然可以防止无意中尝试修改const值.C ++仍然不允许分配char **const char **,但它可以让您将char **分配给const char * const *。)

答案 2 :(得分:11)

因为没有人发布解决方案,所以:

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

http://www.parashift.com/c++-faq-lite/const-correctness.html#faq-18.17为什么)

答案 3 :(得分:9)

C++11 draft standard4.4部分的说明中说明了这一点:

  

[注意:如果程序可以将指针T **类型指定给指针   类型为const T **(即,如果允许下面的第1行),程序   可能会无意中修改一个const对象(就像它在第2行上所做的那样)。   例如,

int main() {
const char c = 'c';
char* pc;
const char** pcc = &pc; // #1: not allowed
*pcc = &c;
*pc = 'C'; // #2: modifies a const object
}
     

-end note]

一个有趣的相关问题是Given int **p1 and const int **p2 is p1 == p2 well formed?

注意C++ FAQ也有解释,但我更喜欢标准中的解释。

与说明一致的符合文本如下:

  

转换可以在第一个以外的级别添加cv限定符   多级指针,遵守以下规则:56

     
    

如果存在类型T和,则两个指针类型T1和T2相似     整数n> 0这样:

         
      

T1是cv1,0指向cv1的指针,指向cv1的指针,n-1指向cv1,n       Ť

    
         

         
      

T2是cv2,0指向cv2,1指针指向c·2,n-1指向cv2,n T

    
         

其中每个cvi,j都是const,volatile,const volatile或什么都不是。该     在指针类型中的第一个之后的cv-qualifiers的n元组,​​例如,     指针类型T1中的cv1,1,cv1,2,...,cv1,n称为     指针类型的cv-qualification签名。类型的表达式     当且仅当以下条件时,T1才能转换为T2型     很满意:

         
        
  • 指针类型相似。
  •     
  • 对于每个j> 0,如果const在cv1中,j则const在cv2,j中,并且类似于volatile。
  •     
  • 如果cv1,j和cv2,j不同,那么const在每个cv2中,k为0< k<学家
  •     
  

答案 4 :(得分:6)

这里有两条规则需要注意:

  • 如果T和U属于不同类型,则T*U*之间不存在隐式转换。
  • 您可以隐式地将T*投射到T const *。 (“指向T的指针”可以转换为“指向const T的指针”)。在C ++中如果T也是指针,则此规则也可以应用于它(链接)。

例如:

char**表示:指向char的指针

const char**表示:指向const char指针的指针

由于指向char的指针指向const char的指针是不同的类型,只有const-ness不同,所以不允许使用强制转换。要转换为的正确类型应该是 const指向char的指针

因此,要保持const正确,必须从最右边的星号开始添加const关键字。

因此char**可以投放到char * const *,也可以投放到const char * const *

此链接仅限C ++。在C中,这种链接不起作用,因此在该语言中,您无法正确地转换多个指针级别。