C++ const 指针的意义是什么?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7715371/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 17:23:14  来源:igfitidea点击:

What's the point of const pointers?

c++cpointersconst

提问by R. Ruiz.

I'm not talking about pointers to const values, but const pointers themselves.

我不是在谈论指向 const 值的指针,而是在谈论 const 指针本身。

I'm learning C and C++ beyond the very basic stuff and just until today I realized that pointers are passed by value to functions, which makes sense. This means that inside a function I can make the copied pointer point to some other value without affecting the original pointer from the caller.

我正在学习 C 和 C++,而不是非常基本的东西,直到今天我才意识到指针是按值传递给函数的,这是有道理的。这意味着在函数内部,我可以使复制的指针指向某个其他值,而不会影响调用者的原始指针。

So what's the point of having a function header that says:

那么拥有一个函数头有什么意义:

void foo(int* const ptr);

Inside such a function you cannot make ptr point to something else because it's const and you don't want it to be modified, but a function like this:

在这样的函数中,你不能让 ptr 指向其他东西,因为它是 const 并且你不希望它被修改,而是一个像这样的函数:

void foo(int* ptr);

Does the work just as well! because the pointer is copied anyways and the pointer in the caller is not affected even if you modify the copy. So what's the advantage of const?

工作也一样!因为无论如何都会复制指针,并且即使您修改副本,调用者中的指针也不会受到影响。那么const有什么好处呢?

回答by tenfour

constis a tool which you should use in pursuit of a very important C++ concept:

const是一个工具,您应该使用它来追求一个非常重要的 C++ 概念:

Find bugs at compile-time, rather than run-time, by getting the compiler to enforce what you mean.

通过让编译器强制执行您的意思,在编译时而不是运行时发现错误。

Even though it doesn't change the functionality, adding constgenerates a compiler error when you're doing things you didn't mean to do. Imagine the following typo:

即使它不会改变功能,const当你在做你不想做的事情时,添加会产生一个编译器错误。想象一下下面的错字:

void foo(int* ptr)
{
    ptr = 0;// oops, I meant *ptr = 0
}

If you use int* const, this would generate a compiler error because you're changing the value to ptr. Adding restrictions via syntax is a good thing in general. Just don't take it too far -- the example you gave is a case where most people don't bother using const.

如果您使用int* const,这将产生编译器错误,因为您将值更改为ptr。通过语法添加限制通常是一件好事。只是不要太过分——你给出的例子是大多数人不打扰使用const.

回答by Konrad Rudolph

I make a point of using onlyconstarguments because this enables more compiler checks: if I accidentally re-assign an argument value inside the function, the compiler bites me.

我强调使用const参数,因为这可以进行更多的编译器检查:如果我不小心在函数内部重新分配了一个参数值,编译器会咬我。

I rarely reuse variables, it's cleaner to create new variables to hold new values, so essentially allmy variable declarations are const(except for some cases such as loop variables where constwould prevent the code from working).

我很少重用变量,创建新变量来保存新值更干净,所以基本上我所有的变量声明都是const(除了某些情况,例如const会阻止代码工作的循环变量)。

Note that this makes only sense in the definitionof a function. It doesn't belong in the declaration, which is what the user sees. And the user doesn't care whether I use constfor parameters inside the function.

请注意,这仅在函数定义中才有意义。它不属于声明,这是用户看到的。并且用户并不关心我是否const在函数内部使用了参数。

Example:

例子:

// foo.h
int frob(int x);
// foo.cpp
int frob(int const x) {
   MyConfigType const config = get_the_config();
   return x * config.scaling;
}

Notice how both the argument and the local variable are const. Neither is necessarybut with functions that are even slightly larger, this has repeatedly saved me from making mistakes.

注意参数和局部变量是如何const。两者都不是必需的,但函数甚至稍大,这使我一再避免犯错误。

回答by Kerrek SB

Your question touches on something more general: Should function arguments be const?

你的问题涉及更普遍的问题:函数参数应该是常量吗?

The constness of value arguments (like your pointer) is an implementation detail, and it does notform part of the function declaration. This means that your function is always this:

值参数(如您的指针)常量性是一个实现细节,它并没有形成函数声明的一部分。这意味着您的功能始终是这样的:

void foo(T);

It is entirely up to the implementerof the function whether she wants to use the functions-scope argument variable in a mutable or in a constant way:

是否要以可变或常量方式使用函数作用域参数变量,完全取决于函数的实现者:

// implementation 1
void foo(T const x)
{
  // I won't touch x
  T y = x;
  // ...
}

// implementation 2
void foo(T x)
{
  // l33t coding skillz
  while (*x-- = zap()) { /* ... */ }
}

So, follow the simple rule to never put constin the declaration (header), and put it in the definition (implementation) if you don't want or need to modify the variable.

所以,遵循简单的规则,永远不要放在const声明(头)中,如果你不想或不需要修改变量,就把它放在定义(实现)中。

回答by David Rodríguez - dribeas

The top level const qualifier is discarded in declarations, so the declarations in the question declare exactly the same function. On the other hand, in the definition(implementation) the compiler will verify that if you mark the pointer as const, it is not modified inside the body of the function.

声明中丢弃了顶级 const 限定符,因此问题中的声明声明了完全相同的函数。另一方面,在定义(实现)中,编译器将验证如果将指针标记为 const,则不会在函数体内修改它。

回答by cnicutar

You're right, for the caller it makes absolutely no difference. But for the writer of the function it can be a safety net "okay, I need to make sure I don't make this point to the wrong thing". Not very useful but not useless either.

你是对的,对于调用者来说,这完全没有区别。但是对于函数的作者来说,它可以是一个安全网“好吧,我需要确保我没有把这点指向错误的事情”。不是很有用,但也不是没用。

It's basically the same as having an int const the_answer = 42in your program.

它与int const the_answer = 42在您的程序中使用 an 基本相同。

回答by Lundin

There is a lot to the constkeyword, it is a rather complex one. Generally, adding a lot of const to your program is considered good programming practice, search the web for "const correctness" and you'll find plenty of info about that.

const关键字有很多,它是一个相当复杂的关键字。通常,在您的程序中添加大量 const 被认为是良好的编程习惯,在网上搜索“const 正确性”,您会找到大量相关信息。

The const keyword is a so-called "type qualifier", others are volatileand restrict. At least volatile follows the same (confusing) rules as const.

const 关键字是所谓的“类型限定符”,其他是volatileand restrict。至少 volatile 遵循与 const 相同(令人困惑)的规则。



First of all, the const keyword serves two purposes. The most obvious one is to protect data (and pointers) from intentional or accidental misuse by making them read-only. Any attempt to modify a const variable will be spotted by the compiler at compile-time.

首先,const 关键字有两个目的。最明显的一种方法是通过将数据(和指针)设为只读来保护数据(和指针)免遭有意或无意的误用。编译器会在编译时发现任何修改 const 变量的尝试。

But there is also another purpose in any system with read-only memory, namely to ensure that a certain variable is allocated inside such memory - it could be EEPROM or flash for example. These are known as non-volatile memories, NVM. A variable allocated in NVM will still of course follow all the rules of a const variable.

但在任何具有只读内存的系统中还有另一个目的,即确保在此类内存中分配某个变量 - 例如,它可以是 EEPROM 或闪存。这些被称为非易失性存储器,NVM。在 NVM 中分配的变量当然仍会遵循 const 变量的所有规则。

There are several different ways to use the constkeyword:

有几种不同的使用const关键字的方法:

Declare a constant variable.

声明一个常量变量。

This can be done either as

这可以作为

const int X=1; or
int const X=1;

These two forms are completely equivalent. The latter style is considered bad style and should not be used.

这两种形式是完全等价的。后一种风格被认为是不好的风格,不应使用。

The reason why the second row is considered bad style, is probably because "storage-class specifiers" such as static and extern also can be declared afterthe actual type, int staticetc. But doing so for storage-class specifiers is labelled as an obsolete feature by the C committee (ISO 9899 N1539 draft, 6.11.5). Therefore, for the sake of consistency one should not write type qualifiers in that manner either. It serves no other purpose but to confuse the reader anyhow.

第二行之所以被认为是不好的风格,可能是因为“存储类说明符”如静态和外部也可以在实际类型之后声明,int static等等。但对存储类说明符这样做被标记为过时的特性由 C 委员会(ISO 9899 N1539 草案,6.11.5)。因此,为了一致性起见,也不应该以这种方式编写类型限定符。它没有其他目的,但无论如何都会使读者感到困惑。

Declare a pointer to a constant variable.

声明一个指向常量变量的指针。

const int* ptr = &X;

This means that the contents of 'X' cannot be modified. This is the normal way you declare pointers like this, mainly as part of function parameters for "const correctness". Because 'X' doesn't actually have to be declared as const, it could be any variable. In other words you can always "upgrade" a variable to const. Technically, C also allows downgrading from const to a plain variable by explicit typecasts, but doing so is considered bad programming and compilers usually give warnings against it.

这意味着不能修改“X”的内容。这是您像这样声明指针的正常方式,主要是作为“常量正确性”的函数参数的一部分。因为 'X' 实际上不必声明为 const,它可以是任何变量。换句话说,您始终可以将变量“升级”为 const。从技术上讲,C 还允许通过显式类型转换从 const 降级为普通变量,但这样做被认为是糟糕的编程,编译器通常会针对它发出警告。

Declare a constant pointer

声明一个常量指针

int* const ptr = &X;

This means that the pointer itselfis constant. You can modify what it points at, but you cannot modify the pointer itself. This doesn't have many uses, there are a few, like ensuring that a pointer-pointed-at (pointer-to-pointer) doesn't have it's address changed while passed as parameter to a function. You'll have to write something not-too-readable like this:

这意味着指针本身是常量。您可以修改它指向的内容,但不能修改指针本身。这没有很多用途,有一些用途,例如确保指针指向(指针到指针)在作为参数传递给函数时不会更改其地址。你必须写一些不太可读的东西:

void func (int*const* ptrptr)

I doubt many C programmers can get the const and * right in there. I know Ican't - I had to check with GCC. I think that's why you rarely ever see that syntax for pointer-to-pointer, even though it is considered good programming practice.

我怀疑许多 C 程序员能否在其中获得 const 和 *。我知道不能 - 我不得不与 GCC 核对。我认为这就是为什么你很少看到指针到指针的语法,即使它被认为是很好的编程实践。

Constant pointers can also be used to ensure that the pointer variable itself is declared in read-only memory, for example you could want to declare some sort of pointer-based lookup table and allocate it in NVM.

常量指针还可用于确保指针变量本身在只读内存中声明,例如,您可能想要声明某种基于指针的查找表并在 NVM 中分配它。

And of course, as indicated by other answers, constant pointers can also be used to enforce "const correctness".

当然,正如其他答案所示,常量指针也可用于强制执行“常量正确性”。

Declare a constant pointer to constant data

声明一个指向常量数据的常量指针

const int* const ptr=&X;

This is the two pointer types described above combined, with all attributes of them both.

这是上面描述的两种指针类型的组合,以及它们的所有属性。

Declare a read-only member function (C++)

声明只读成员函数 (C++)

Since this is tagged C++, I should also mention that you can declare member functions of a class as const. This means that the function isn't allowed to modify any other member of the class when it is called, which both prevents the programmer of the class from accidental errors but also informs the caller of the member function that they won't be messing anything up by calling it. The syntax is:

由于这是标记为 C++,我还应该提到您可以将类的成员函数声明为 const。这意味着函数在被调用时不允许修改类的任何其他成员,这既可以防止类的程序员意外错误,也可以通知成员函数的调用者他们不会弄乱任何东西通过调用它。语法是:

void MyClass::func (void) const;

回答by justin

...today I realized that pointers are passed by value to functions, which makes sense.

...今天我意识到指针是按值传递给函数的,这是有道理的。

(imo) it really doesn't make sense as the default. the more sensible default is to pass as non-reassignable pointer (int* const arg). that is, i would have preferred that pointers passed as arguments were implicitly declared const.

(imo) 作为默认设置确实没有意义。更明智的默认值是作为不可重新分配的指针 ( int* const arg)传递。也就是说,我宁愿将作为参数传递的指针隐式声明为 const。

So what's the advantage of const?

那么const有什么好处呢?

the advantage is that it's easy enough and sometimes unclear when you do modify the address the argument points to, such that you can introduce a bug when it is not const rather easily. altering the address is atypical. it's clearer to create a local variable if your intent is to modify the address. as well, raw pointer manipulation is an easy way to introduce bugs.

优点是当你修改参数指向的地址时它很容易并且有时不清楚,这样你就可以在它不是 const 时很容易地引入错误。更改地址是不典型的。如果您的意图是修改地址,则创建局部变量会更清楚。同样,原始指针操作是引入错误的一种简单方法。

so it's clearer to pass by immutable address and create a copy (in those atypical cases) when you want to alter the address the argument points to:

因此,当您想要更改参数指向的地址时,传递不可变地址并创建副本(在那些非典型情况下)会更清楚:

void func(int* const arg) {
    int* a(arg);
    ...
    *a++ = value;
}

adding that local is virtually free, and it reduces the chance for errors, while improving readability.

添加本地几乎是免费的,它减少了出错的机会,同时提高了可读性。

at a higher level: if you are manipulating the argument as an array, it's typically clearer and less error prone to the client to declare the argument as a container/collection.

在更高级别上:如果您将参数作为数组进行操作,那么客户端将参数声明为容器/集合通常会更清晰且不易出错。

in general, adding const to values, arguments, and addresses is a good idea because you don't always realize the side effects, which the compiler happily enforces. therefore, it's as useful as const as used in other several other cases (e.g. the question is similar to 'Why should I declare values const?'). fortunately, we also have references, which cannot be reassigned.

通常,将 const 添加到值、参数和地址是一个好主意,因为您并不总是意识到编译器很乐意强制执行的副作用。因此,它与在其他几种情况下使用的 const 一样有用(例如,问题类似于“为什么我应该声明值为 const?”)。幸运的是,我们也有无法重新分配的引用。

回答by Dan Haynes

If you do embedded systems or device driver programming where you have memory mapped devices then both forms of 'const' are often used, one to prevent the pointer from being reassigned (since it points to a fixed hardware address.) and, if the peripheral register it points to is a read-only hardware register then another const will detect a lot of errors at compile time rather than runtime.

如果您在有内存映射设备的情况下进行嵌入式系统或设备驱动程序编程,那么经常使用两种形式的“const”,一种是防止指针被重新分配(因为它指向固定的硬件地址)。 register 它指向的是一个只读的硬件寄存器,然后另一个 const 将在编译时而不是运行时检测到很多错误。

A read-only 16 bit peripheral chip register might look something like:

只读 16 位外围芯片寄存器可能类似于:

static const unsigned short *const peripheral = (unsigned short *)0xfe0000UL;

static const unsigned short *const peripheral = (unsigned short *)0xfe0000UL;

Then you can easily read the hardware register without having to resort to assembly language:

然后您可以轻松读取硬件寄存器而无需求助于汇编语言:

input_word = *peripheral;

input_word = *peripheral;

回答by zar

Your question is really more about why define any variable as a const not just const pointer parameter to a function. The same rules apply here as when you define any variable as constant, if its a parameter to function or member variable or a local variable.

您的问题实际上更多是关于为什么将任何变量定义为 const 而不仅仅是函数的 const 指针参数。如果将任何变量定义为常量,则此处适用相同的规则,如果它是函数的参数、成员变量或局部变量。

In your particular case, functionally it doesn't make difference like in many other cases when you declare a local variable as const but it does put a restriction that you can't modify this variable.

在您的特定情况下,从功能上讲,当您将局部变量声明为 const 时,它在功能上与许多其他情况没有区别,但它确实限制了您无法修改此变量。

回答by pmg

Same question can be asked about any other type (not just pointers):

可以就任何其他类型(不仅仅是指针)提出同样的问题:

/* Why is n const? */
const char *expand(const int n) {
    if (n == 1) return "one";
    if (n == 2) return "two";
    if (n == 3) return "three";
    return "many";
}