为什么在复制对象时忽略顶级常量

Why are top level Constants ignored while copying objects?

本文关键字:常量 复制 对象 为什么      更新时间:2023-10-16

我正在阅读C++初级读本,我一直在这个主题上。上面写着

int i=0;
const int ci=42; //const is top level.
const int *p2=&ci; //const is low level.
const int *const p3=p2; //rightmost const is top level,left one is low level. 
int *p=p3 //error.
p2=p3 //ok:p2 has the same low level constant qualification as p3.
int &r=ci; //error: can't bind an ordinary int to const int object
const int &r2=i; //ok:can bind const int to plain int.

现在,如果在最后一条语句中忽略了顶级常量,那么它应该会给出一个错误,因为&r2和i的低级常量限定不相同。为什么最后一次停留是正确的??

你在一个问题中提出了10亿个问题,但我会总结一下。

  • 这些:

    int &r=ci; //error: can't bind an ordinary int to const int object
    const int &r2=i; //ok:can bind const int to plain int.
    

    遵循引用初始化的规则。左侧需要具有与右侧相同或更大的cv资格。

  • 这些:

    const int *p2=&ci; //const is low level.
    const int *const p3=p2; //rightmost const is top level,left one is low level. 
    int *p=p3 //error.
    p2=p3 //ok:p2 has the same low level constant qualification as p3.
    

    遵循资格转换规则。本质上,他们试图保持常量的正确性。像p = p3这样的任务肯定做不到。

我认为,如果你放弃"顶级"answers"低级"const的东西,你会更容易理解规则,因为它们显然无助于你理解这里发生的事情。

在处理const声明时,需要向后看。不幸的是,它有一个例外:由于历史原因,允许使用const int,但其含义与int const相同。

下面,const"回头看"int,所以p指向一个不能更改的int。

int const * p; 

这里,const"回头看"int *,所以p不允许指向其他任何东西,但它现在指向的东西可以通过p更改。

int i = 5; int j = 5;
int * const p = &i;
*p = 6;       // ok, you can still modify `i` through `p`
p = &j;       // error because you can't change what `p` points at

这里,p是指向常量int的常量指针。p不允许更改,它指向的内容也不能更改。

int i = 5; int j = 5
int const * const p = &i;
*p = 6;       // error, promised not to makes changes through `p`
p = &j;       // error `p` is stuck to `i`

当把一件事分配给另一件事时,规则是不能违背承诺。int const承诺int永远不会改变。如果你尝试这个:

int const i = 5;
int * p = &i;      // error

如果编译器允许你这样做,那么你就可以通过做这个来打破i永远不会改变的承诺

*p = 6;

现在i将从5变为6,打破了i永远不会改变的承诺。

反过来也没关系,因为你没有违背任何承诺。在这种情况下,您只是承诺当您通过指针p访问i时不会更改它

int i = 5;
int const * p = &i;
*p = 6;             // error, because we promised not to change `i` through `p`
i = 6;              // ok, because `i` itself is not const

const作为内置的安全检查非常重要。如果您声明为const的内容发生更改,编译器将给您一个错误。您可以将类的方法声明为const,这意味着该方法不会更改类中的任何数据。很容易忘记并在以后修改该方法以更改类中的某些内容,但编译器会提醒您。

这对优化也很重要。如果编译器知道某个东西是const,它可以进行大量简化假设以加快代码的速度。