什么是顶层const限定符?

67

C++中在“顶层”上的限定符 const 是什么意思?

还有其他级别吗?

例如:

int const *i;
int *const i;
int const *const i;

我不知道你所说的例子是什么,但我添加了一些我熟悉的const限定符。 - user103214
4个回答

65

顶层const限定符影响对象本身。其他限定符仅适用于指针和引用。它们不会使对象成为常量,只能防止通过指针或引用进行修改。因此:

char x;
char const* p = &x;

这不是顶层const,也没有任何对象是不可变的。表达式*p不能用于修改x,但其他表达式可以;x不是const。就此而言。

*const_cast<char*>( p ) = 't'

这个术语是合法且定义明确的。

但是

char const x = 't';
char const* p = &x;

这次,x 有一个顶层的 const,所以 x 是不可变的。没有表达式被允许改变它(即使使用 const_cast)。编译器可以将 x 放在只读内存中,并且可以假设无论其他代码如何,x 的值永远不会改变。
要给指针添加顶层的 const,您需要写成:
char x = 't';
char *const p = &x;

在这种情况下,p 将永远指向 x;任何试图更改此内容的尝试都是未定义行为(并且编译器可能会将 p 放入只读内存中,或者假定 *p 引用 x,而不考虑任何其他代码)。

9
另外一点:在编写函数时,参数的顶层限定符会被忽略。这意味着 void foo(char const)void foo(char) 是同一个函数(实际上它们可以互换使用)。原因是由于参数是通过复制传递的,调用者不关心副本是否可以修改,因此对她来说是透明的。 - Matthieu M.
8
@MatthieuM. 这个观点不错,但陈述并非完全正确。在声明和函数类型中,顶层限定符会被忽略。然而,在定义中,它们仍然像通常情况下一样在函数内起作用。(当匹配异常捕获时,顶层限定符也被typeid和模板参数所忽略,并且可能在我已经忘记的其他情况下也是如此。实际上,在非类类型的返回值上它们也没有影响。) - James Kanze
关于最后一个例子,即 const pp=0; 是试图改变 p 的一种尝试,但它并不具有未定义行为,只是不良形式。 - Ruslan

16

两种const的级别分别为: * 低层const * 顶层const

您应该通过引用和指针来了解顶层和低层const,因为这是它们相关的地方。

int i = 0;
int *p = &i;
int *const cp = &i;
const int *pc = &i;
const int *const cpc = &i;
在上述代码中,有4种不同的指针声明。让我们逐个来看, int *p:普通指针可用于更改基础对象并可重新分配。 int *const cp(顶层const):常量指针可用于更改基础对象,但不能重新分配(不能将其更改为指向另一个对象)。 const int *pc(低级const):指向常量的指针不能用于更改基础对象,但它本身可以被重新分配。 const int *const cpc(顶层和低级const):常量指针指向常量既不能用于更改基础对象,也不能本身被重新分配。
此外,当分配给另一个对象时,顶层const总是被忽略,而低级const不会被忽略。
int i = 0;
const int *pc = &i;
int *const cp = &i;

int *p1 = cp; // allowed
int *p2 = pc; // error, pc has type const int*
希望这有所帮助 :) 顺便提一下,C++ Primer也包含了很多相关信息!!!

1
非常感谢,这是最清晰的解释。顺便说一下,《C++ Primer》是引领我来到这里的书籍。 - Aghiad Alzein
1
你应该通过引用和指针查看顶层和底层的const,因为这是它们相关的地方。好的,但是没有人给出过关于引用的例子。 - openyourmind

14

据我所解释的,鉴于:

[const] TYPE * [const] VARIABLE

VARIABLE用来指向TYPE类型的data,通过*VARIABLE实现

*或多个*中画一条线

  1. 如果在*左侧有一个const,它适用于数据,则数据不能被更改:*VARIABLE除初始化外不能被赋值
  2. 如果在*右侧有一个const,它适用于VARIABLE,则VARIABLE所指向的内容不能被更改:VARIABLE除初始化外不能被赋值

因此:

          |              left  right
int       *       i1;
          |              no    no     can change *i1 and i1

int const *       i2;     
          |              yes   no     cannot change *i2 but can change i2

int       * const i3;
          |              no    yes    can change *i3 but i3 cannot be changed

int const * const i4;
          |              yes   yes    cannot change *i4 or i4

4
const 绑定到左边,除非左边没有任何东西,那么它就会绑定到右边。 - sp2danny

13

int *const iconst 放在顶层,而 int const *i 不是。

第一个说指针 i 本身是不可变的,而第二个说指针所指向的内存是不可变的。

无论何时 const 出现在标识符类型的前面或后面,那都被视为顶级限定符。


1
优秀且清晰的回答。PS:int const *i 等同于 const int *i(都是低层次的 const)。我通常使用 const int *i(低层次)来更明确地区分其 const 级别,与 int *const i(顶层)区别开来。 - dotslash
我很难理解“无论何时,当const出现在标识符的类型之前或之后时,都被视为顶层限定符。”这是否适用于int const *i,因为const出现在标识符的类型中间,在这种情况下是int * - 24n8
@24n8 我也在努力理解。 - openyourmind

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接