在函数参数上使用 const 有什么影响吗? 为什么它不影响函数签名?

发布于 2024-07-05 01:27:26 字数 460 浏览 6 评论 0原文

例如,想象一个采用单个布尔参数的简单变元:

void SetValue(const bool b) { my_val_ = b; }

该 const 实际上有任何影响吗? 就我个人而言,我选择广泛使用它,包括参数,但在这种情况下,我想知道它是否有什么区别。

我还惊讶地发现您可以在函数声明中的参数中省略 const 但可以将其包含在函数定义中,例如:

.h 文件

void func(int n, long l);

.cpp文件

void func(const int n, const long l) { /* ... */ }

这是有原因的吗? 对我来说这似乎有点不寻常。

For example, imagine a simple mutator that takes a single boolean parameter:

void SetValue(const bool b) { my_val_ = b; }

Does that const actually have any impact? Personally I opt to use it extensively, including parameters, but in this case I wonder if it makes any difference.

I was also surprised to learn that you can omit const from parameters in a function declaration but can include it in the function definition, e.g.:

.h file

void func(int n, long l);

.cpp file

void func(const int n, const long l) { /* ... */ }

Is there a reason for this? It seems a little unusual to me.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(30

旧情别恋 2024-07-12 01:27:27

作为需要使用具有 50 多个公开函数的 C++ 程序以及偶尔使用 const 限定符的 .h 文件的 VB.NET 程序员,很难知道何时使用 ByRef 或 ByVal 访问变量。

当然,程序会通过在出错的行上生成异常错误来告诉您,但是您需要猜测 2-10 个参数中哪一个是错误的。

因此,现在我面临着一项令人厌恶的任务,即试图说服开发人员他们应该以允许轻松创建所有 VB.NET 函数定义的自动化方法的方式真正定义变量(在 .h 文件中)。 然后他们会沾沾自喜地说:“阅读……文档。”

我编写了一个 awk 脚本来解析 .h 文件,并创建所有 Declare Function 命令,但没有指示哪些变量是 R/O 还是 R/W,它只完成了一半的工作。

编辑:

在另一位用户的鼓励下,我添加了以下内容;

这是一个(IMO)格式不良的 .h 条目的示例;

typedef int (EE_STDCALL *Do_SomethingPtr)( int smfID, const char* cursor_name, const char* sql );

我的脚本生成的 VB;

    Declare Function Do_Something Lib "SomeOther.DLL" (ByRef smfID As Integer, ByVal cursor_name As String, ByVal sql As String) As Integer

请注意第一个参数上缺少“const”。 如果没有它,程序(或其他开发人员)就不会知道第一个参数应该传递“ByVal”。 通过添加“const”,它使 .h 文件自我记录,以便使用其他语言的开发人员可以轻松编写工作代码。

Being a VB.NET programmer that needs to use a C++ program with 50+ exposed functions, and a .h file that sporadically uses the const qualifier, it is difficult to know when to access a variable using ByRef or ByVal.

Of course the program tells you by generating an exception error on the line where you made the mistake, but then you need to guess which of the 2-10 parameters is wrong.

So now I have the distasteful task of trying to convince a developer that they should really define their variables (in the .h file) in a manner that allows an automated method of creating all of the VB.NET function definitions easily. They will then smugly say, "read the ... documentation."

I have written an awk script that parses a .h file, and creates all of the Declare Function commands, but without an indicator as to which variables are R/O vs R/W, it only does half the job.

EDIT:

At the encouragement of another user I am adding the following;

Here is an example of a (IMO) poorly formed .h entry;

typedef int (EE_STDCALL *Do_SomethingPtr)( int smfID, const char* cursor_name, const char* sql );

The resultant VB from my script;

    Declare Function Do_Something Lib "SomeOther.DLL" (ByRef smfID As Integer, ByVal cursor_name As String, ByVal sql As String) As Integer

Note the missing "const" on the first parameter. Without it, a program (or another developer) has no Idea the 1st parameter should be passed "ByVal." By adding the "const" it makes the .h file self documenting so that developers using other languages can easily write working code.

梦开始←不甜 2024-07-12 01:27:27

仅当参数通过引用(即引用或指针)传递时,Const 参数才有用。 当编译器看到 const 参数时,它会确保参数中使用的变量不会在函数体内被修改。 为什么有人想要将按值参数设置为常量? :-)

Const parameter is useful only when the parameter is passed by reference i.e., either reference or pointer. When compiler sees a const parameter, it make sure that the variable used in the parameter is not modified within the body of the function. Why would anyone want to make a by-value parameter as constant? :-)

我为君王 2024-07-12 01:27:27

使用 const 需要记住的一点是,从一开始就将事物设为 const 比稍后尝试将它们放入要容易得多。

当您希望某些内容保持不变时,请使用 const - 它是一个附加提示,描述您的函数的作用和期望。 我见过很多 C API 可以处理其中的一些,尤其是那些接受 C 字符串的 API!

与标题相比,我更倾向于省略 cpp 文件中的 const 关键字,但由于我倾向于剪切+粘贴它们,因此它们会保留在两个位置。 我不知道为什么编译器允许这样做,我猜这是编译器的事情。 最佳实践肯定是将 const 关键字放在两个文件中。

the thing to remember with const is that it is much easier to make things const from the start, than it is to try and put them in later.

Use const when you want something to be unchanged - its an added hint that describes what your function does and what to expect. I've seen many an C API that could do with some of them, especially ones that accept c-strings!

I'd be more inclined to omit the const keyword in the cpp file than the header, but as I tend to cut+paste them, they'd be kept in both places. I have no idea why the compiler allows that, I guess its a compiler thing. Best practice is definitely to put your const keyword in both files.

牵你的手,一向走下去 2024-07-12 01:27:27

由于参数是按值传递的,因此从调用函数的角度来看,是否指定 const 没有任何区别。将按值传递参数声明为 const 基本上没有任何意义。

As parameters are being passed by value,it doesnt make any difference if you specify const or not from the calling function's perspective.It basically does not make any sense to declare pass by value parameters as const.

两仪 2024-07-12 01:27:27

你的例子中的所有常量都没有目的。 C++ 默认情况下是按值传递的,因此该函数获取这些整数和布尔值的副本。 即使函数确实修改了它们,调用者的副本也不会受到影响。

所以我会避免额外的const,因为

  • 它们是多余的,
  • 它们混乱不堪
    文本
  • 他们阻止我
    改变传入的值
    它可能有用或有效的情况。

All the consts in your examples have no purpose. C++ is pass-by-value by default, so the function gets copies of those ints and booleans. Even if the function does modify them, the caller's copy is not affected.

So I'd avoid extra consts because

  • They're redudant
  • They clutter up
    the text
  • They prevent me from
    changing the passed in value in
    cases where it might be useful or efficient.
尝蛊 2024-07-12 01:27:27

我知道这个问题“有点”过时,但当我遇到这个问题时,其他人将来也可能会这样做......我仍然怀疑这个可怜的家伙会在这里列出来阅读我的评论:)

在我看来我们仍然太局限于C风格的思维方式。 在 OOP 范式中,我们使用的是对象,而不是类型。 Const 对象在概念上可能与非 const 对象不同,特别是在逻辑 const 的意义上(与按位 const 相对)。 因此,即使函数参数的 const 正确性(也许)在 POD 中过于谨慎,但在对象中却并非如此。 如果一个函数与 const 对象一起工作,它应该这样说。 请考虑以下代码片段

#include <iostream>

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class SharedBuffer {
private:

  int fakeData;

  int const & Get_(int i) const
  {

    std::cout << "Accessing buffer element" << std::endl;
    return fakeData;

  }

public:

  int & operator[](int i)
  {

    Unique();
    return const_cast<int &>(Get_(i));

  }

  int const & operator[](int i) const
  {

    return Get_(i);

  }

  void Unique()
  {

    std::cout << "Making buffer unique (expensive operation)" << std::endl;

  }

};

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void NonConstF(SharedBuffer x)
{

  x[0] = 1;

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void ConstF(const SharedBuffer x)
{

  int q = x[0];

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int main()
{

  SharedBuffer x;

  NonConstF(x);

  std::cout << std::endl;

  ConstF(x);

  return 0;

}

:您可能会认为 (const) 引用在这里更合适,并为您提供相同的行为。 嗯,对。 只是给出了与我在其他地方看到的不同的图片......

I know the question is "a bit" outdated but as I came accross it somebody else may also do so in future... ...still I doubt the poor fellow will list down here to read my comment :)

It seems to me that we are still too confined to C-style way of thinking. In the OOP paradigma we play around with objects, not types. Const object may be conceptually different from a non-const object, specifically in the sense of logical-const (in contrast to bitwise-const). Thus even if const correctness of function params is (perhaps) an over-carefulness in case of PODs it is not so in case of objects. If a function works with a const object it should say so. Consider the following code snippet

#include <iostream>

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class SharedBuffer {
private:

  int fakeData;

  int const & Get_(int i) const
  {

    std::cout << "Accessing buffer element" << std::endl;
    return fakeData;

  }

public:

  int & operator[](int i)
  {

    Unique();
    return const_cast<int &>(Get_(i));

  }

  int const & operator[](int i) const
  {

    return Get_(i);

  }

  void Unique()
  {

    std::cout << "Making buffer unique (expensive operation)" << std::endl;

  }

};

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void NonConstF(SharedBuffer x)
{

  x[0] = 1;

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void ConstF(const SharedBuffer x)
{

  int q = x[0];

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int main()
{

  SharedBuffer x;

  NonConstF(x);

  std::cout << std::endl;

  ConstF(x);

  return 0;

}

ps.: you may argue that (const) reference would be more appropriate here and gives you the same behaviour. Well, right. Just giving a different picture from what I could see elsewhere...

清音悠歌 2024-07-12 01:27:27

我不会把 const 放在这样的参数上 - 每个人都知道布尔值(与 boolean& 相对)是常量,所以添加它会让人们思考“等等,什么?” 或者甚至您通过引用传递参数。

I wouldn't put const on parameters like that - everyone already knows that a boolean (as opposed to a boolean&) is constant, so adding it in will make people think "wait, what?" or even that you're passing the parameter by reference.

单身狗的梦 2024-07-12 01:27:27

如果参数按值传递(并且不是引用),则该参数是否声明为 const 通常没有太大区别(除非它包含引用成员——这对于内置类型来说不是问题)。 如果参数是引用或指针,通常最好保护引用/指向的内存,而不是指针本身(我认为你不能使引用本身成为常量,但这并不重要,因为你不能改变引用者) 。
将所有可以保护的东西作为 const 似乎是个好主意。 如果参数只是 POD(包括内置类型)并且它们不可能进一步更改(例如,在您的示例中为 bool 参数),您可以省略它,而不必担心犯错误。

我不知道 .h/.cpp 文件声明差异,但它确实有一定意义。 在机器代码级别,没有什么是“const”的,因此如果将函数(在 .h 中)声明为非 const,则代码与将其声明为 const 相同(不考虑优化)。 但是,它可以帮助您让编译器确保您不会更改函数 (.ccp) 实现中的变量值。 当您从允许更改的接口继承但不需要更改参数来实现所需的功能时,它可能会很方便。

If the parameter is passed by value (and is not a reference), usually there is not much difference whether the parameter is declared as const or not (unless it contains a reference member -- not a problem for built-in types). If the parameter is a reference or pointer, it is usually better to protect the referenced/pointed-to memory, not the pointer itself (I think you cannot make the reference itself const, not that it matters much as you cannot change the referee).
It seems a good idea to protect everything you can as const. You can omit it without fear of making a mistake if the parameters are just PODs (including built-in types) and there is no chance of them changing further along the road (e.g. in your example the bool parameter).

I didn't know about the .h/.cpp file declaration difference, but it does make some sense. At the machine code level, nothing is "const", so if you declare a function (in the .h) as non-const, the code is the same as if you declare it as const (optimizations aside). However, it helps you to enlist the compiler that you will not change the value of the variable inside the implementation of the function (.ccp). It might come handy in the case when you're inheriting from an interface that allows change, but you don't need to change to parameter to achieve the required functionality.

熊抱啵儿 2024-07-12 01:27:27

总结一下:

  • “通常 const 值传递是无用的,充其量是具有误导性的。” 来自 GOTW006
  • 但您可以将它们添加到 .cpp 中,就像处理变量一样。
  • 请注意,标准库不使用 const。 例如std::vector::at(size_type pos)。 对标准库来说足够好的对我来说也有好处。

To summarize:

  • "Normally const pass-by-value is unuseful and misleading at best." From GOTW006
  • But you can add them in the .cpp as you would do with variables.
  • Note that the standard library doesn't use const. E.g. std::vector::at(size_type pos). What's good enough for the standard library is good for me.
汐鸠 2024-07-12 01:27:27

我倾向于尽可能使用 const。 (或目标语言的其他适当的关键字。)我这样做纯粹是因为它允许编译器进行额外的优化,否则它无法进行。 由于我不知道这些优化可能是什么,所以我总是这样做,即使它看起来很愚蠢。

据我所知,编译器很可能会看到一个 const 值参数,并说:“嘿,这个函数无论如何都不会修改它,所以我可以通过引用传递并节省一些时钟周期。” 我认为它永远不会做这样的事情,因为它改变了函数签名,但它说明了这一点。 也许它会执行一些不同的堆栈操作或其他操作...重点是,我不知道,但我确实知道尝试比编译器更聪明只会让我感到羞耻。

C++ 有一些额外的包袱,带有常量正确性的思想,因此它变得更加重要。

I tend to use const wherever possible. (Or other appropriate keyword for the target language.) I do this purely because it allows the compiler to make extra optimizations that it would not be able to make otherwise. Since I have no idea what these optimizations may be, I always do it, even where it seems silly.

For all I know, the compiler might very well see a const value parameter, and say, "Hey, this function isn't modifying it anyway, so I can pass by reference and save some clock cycles." I don't think it ever would do such a thing, since it changes the function signature, but it makes the point. Maybe it does some different stack manipulation or something... The point is, I don't know, but I do know trying to be smarter than the compiler only leads to me being shamed.

C++ has some extra baggage, with the idea of const-correctness, so it becomes even more important.

浮世清欢 2024-07-12 01:27:27

也许这不是一个有效的论点。 但是如果我们在函数内增加 const 变量的值,编译器将会给出一个错误:
错误:只读参数增量”。 这意味着我们可以使用 const 关键字来防止意外修改函数内的变量(我们不应该这样做/只读)。 因此,如果我们在编译时不小心这样做了,编译器会让我们知道。 如果您不是唯一参与该项目的人,这一点尤其重要。

May be this wont be a valid argument. but if we increment the value of a const variable inside a function compiler will give us an error:
"error: increment of read-only parameter". so that means we can use const key word as a way to prevent accidentally modifying our variables inside functions(which we are not supposed to/read-only). so if we accidentally did it at the compile time compiler will let us know that. this is specially important if you are not the only one who is working on this project.

伤痕我心 2024-07-12 01:27:27

在您提到的情况下,它不会影响 API 的调用者,这就是为什么它不常见(并且在标头中没有必要)。 它只会影响你的功能的实现。

这并不是一件特别坏的事情,但好处并没有那么大,因为它不会影响你的 API,而且它会增加输入,所以通常不这样做。

In the case you mention, it doesn't affect callers of your API, which is why it's not commonly done (and isn't necessary in the header). It only affects the implementation of your function.

It's not particularly a bad thing to do, but the benefits aren't that great given that it doesn't affect your API, and it adds typing, so it's not usually done.

命硬 2024-07-12 01:27:27

我不使用 const 作为传值参数。 调用者并不关心你是否修改参数,它是一个实现细节。

真正重要的是,如果方法不修改其实例,则将方法标记为 const。 边做边做,否则你可能会得到很多 const_cast<> 或很多 const_cast<> 。 或者您可能会发现将方法标记为 const 需要更改大量代码,因为它调用了本应标记为 const 的其他方法。

如果我不需要修改局部变量,我也倾向于将它们标记为 const。 我相信它可以通过更容易地识别“移动部分”来使代码更容易理解。

I do not use const for value-passed parametere. The caller does not care whether you modify the parameter or not, it's an implementation detail.

What is really important is to mark methods as const if they do not modify their instance. Do this as you go, because otherwise you might end up with either lots of const_cast<> or you might find that marking a method const requires changing a lot of code because it calls other methods which should have been marked const.

I also tend to mark local vars const if I do not need to modify them. I believe it makes the code easier to understand by making it easier to identify the "moving parts".

唔猫 2024-07-12 01:27:27

关于编译器优化:http://www.gotw.ca/gotw/081.htm

On compiler optimizations: http://www.gotw.ca/gotw/081.htm

深海夜未眠 2024-07-12 01:27:27

如果可以的话我会使用const。 参数的 Const 意味着它们不应该改变它们的值。 这在通过引用传递时尤其有价值。 const for function 声明该函数不应更改类成员。

I use const were I can. Const for parameters means that they should not change their value. This is especially valuable when passing by reference. const for function declares that the function should not change the classes members.

善良天后 2024-07-12 01:27:26

当我以编写 C++ 代码为生时,我尽可能地使用了一切。 使用 const 是帮助编译器为您提供帮助的好方法。 例如,对方法返回值进行 const 操作可以避免拼写错误,例如:

foo() = 42

当您的意思是:

foo() == 42

如果 foo() 被定义为返回非常量引用:

int& foo() { /* ... */ }

编译器会很乐意让您为返回的匿名临时值分配一个值通过函数调用。 使其成为常量:

const int& foo() { /* ... */ }

消除这种可能性。

When I coded C++ for a living I consted everything I possibly could. Using const is a great way to help the compiler help you. For instance, const-ing your method return values can save you from typos such as:

foo() = 42

when you meant:

foo() == 42

If foo() is defined to return a non-const reference:

int& foo() { /* ... */ }

The compiler will happily let you assign a value to the anonymous temporary returned by the function call. Making it const:

const int& foo() { /* ... */ }

Eliminates this possibility.

橘寄 2024-07-12 01:27:26

在 comp.lang.c++.moderated 上的旧“本周大师”文章中对此主题进行了很好的讨论 此处

相应的 GOTW 文章可在 Herb Sutter 的网站此处上找到。

There is a good discussion on this topic in the old "Guru of the Week" articles on comp.lang.c++.moderated here.

The corresponding GOTW article is available on Herb Sutter's web site here.

初见终念 2024-07-12 01:27:26

我在函数参数上使用 const,这些参数是引用(或指针),它们只是 [in] 数据,不会被函数修改。 意思是,使用引用的目的是为了避免复制数据并且不允许更改传递的参数。

在示例中将 const 放在布尔 b 参数上只会对实现施加约束,并且不会对类的接口做出贡献(尽管通常建议不更改参数)。

的函数签名

void foo(int a);

void foo(const int a);

是相同的,这解释了您的 .c 和 .h

Asaf

I use const on function parameters that are references (or pointers) which are only [in] data and will not be modified by the function. Meaning, when the purpose of using a reference is to avoid copying data and not to allow changing the passed parameter.

Putting const on the boolean b parameter in your example only puts a constraint on the implementation and doesn't contribute for the class's interface (although not changing parameters is usually advised).

The function signature for

void foo(int a);

and

void foo(const int a);

is the same, which explains your .c and .h

Asaf

薄暮涼年 2024-07-12 01:27:26

我说const你的值参数。

考虑这个有缺陷的函数:

bool isZero(int number)
{
  if (number = 0)  // whoops, should be number == 0
    return true;
  else
    return false;
}

如果 number 参数是 const,编译器将停止并警告我们该错误。

I say const your value parameters.

Consider this buggy function:

bool isZero(int number)
{
  if (number = 0)  // whoops, should be number == 0
    return true;
  else
    return false;
}

If the number parameter was const, the compiler would stop and warn us of the bug.

杀お生予夺 2024-07-12 01:27:26

如果您使用 ->*.* 运算符,则这是必须的。

它会阻止你写出像

void foo(Bar *p) { if (++p->*member > 0) { ... } }

我现在几乎所做的那样的东西,而且这可能不会达到你的意图。

我想说的是

void foo(Bar *p) { if (++(p->*member) > 0) { ... } }

,如果我在 Bar *p 之间放置一个 const,编译器就会告诉我这一点。

If you use the ->* or .* operators, it's a must.

It prevents you from writing something like

void foo(Bar *p) { if (++p->*member > 0) { ... } }

which I almost did right now, and which probably doesn't do what you intend.

What I intended to say was

void foo(Bar *p) { if (++(p->*member) > 0) { ... } }

and if I had put a const in between Bar * and p, the compiler would have told me that.

我喜欢麦丽素 2024-07-12 01:27:26

啊,一个艰难的。 一方面,声明是一个契约,按值传递 const 参数确实没有意义。 另一方面,如果您查看函数实现,如果您声明参数常量,则将为编译器提供更多优化机会。

Ah, a tough one. On one side, a declaration is a contract and it really does not make sense to pass a const argument by value. On the other hand, if you look at the function implementation, you give the compiler more chances to optimize if you declare an argument constant.

你另情深 2024-07-12 01:27:26

当参数按值传递时,const 毫无意义,因为您不会修改调用者的对象。

通过引用传递时应首选 const,除非函数的目的是修改传递的值。

最后,不修改当前对象(this)的函数可以而且可能应该声明为 const。 示例如下:

int SomeClass::GetValue() const {return m_internalValue;}

这是一个承诺,不会修改应用此调用的对象。 换句话说,您可以调用:

const SomeClass* pSomeClass;
pSomeClass->GetValue();

如果函数不是 const,这将导致编译器警告。

const is pointless when the argument is passed by value since you will not be modifying the caller's object.

const should be preferred when passing by reference, unless the purpose of the function is to modify the passed value.

Finally, a function which does not modify current object (this) can, and probably should be declared const. An example is below:

int SomeClass::GetValue() const {return m_internalValue;}

This is a promise to not modify the object to which this call is applied. In other words, you can call:

const SomeClass* pSomeClass;
pSomeClass->GetValue();

If the function was not const, this would result in a compiler warning.

北斗星光 2024-07-12 01:27:26

将值参数标记为“const”绝对是一个主观的事情。

不过,我实际上更喜欢将值参数标记为 const,就像在您的示例中一样。

void func(const int n, const long l) { /* ... */ }

对我来说,价值在于清楚地表明函数参数值永远不会被函数更改。 它们在开始时和结束时具有相同的值。 对我来说,这是保持函数式编程风格的一部分。

对于一个短函数,在那里使用“const”可以说是浪费时间/空间,因为通常很明显参数没有被函数修改。

然而,对于较大的函数,它是实现文档的一种形式,并且由编译器强制执行。

我可以确定,如果我用“n”和“l”进行一些计算,我可以重构/移动该计算,而不必担心得到不同的结果,因为我错过了一个或两个都发生更改的地方。

由于它是实现细节,因此您不需要在标头中声明值参数 const,就像您不需要声明与实现使用的名称相同的函数参数一样。

Marking value parameters 'const' is definitely a subjective thing.

However I actually prefer to mark value parameters const, just like in your example.

void func(const int n, const long l) { /* ... */ }

The value to me is in clearly indicating that the function parameter values are never changed by the function. They will have the same value at the beginning as at the end. For me, it is part of keeping to a very functional programming sort of style.

For a short function, it's arguably a waste of time/space to have the 'const' there, since it's usually pretty obvious that the arguments aren't modified by the function.

However for a larger function, its a form of implementation documentation, and it is enforced by the compiler.

I can be sure if I make some computation with 'n' and 'l', I can refactor/move that computation without fear of getting a different result because I missed a place where one or both is changed.

Since it is an implementation detail, you don't need to declare the value parameters const in the header, just like you don't need to declare the function parameters with the same names as the implementation uses.

夜雨飘雪 2024-07-12 01:27:26

const 应该是 C++ 中的默认值。
像这样 :

int i = 5 ; // i is a constant

var int i = 5 ; // i is a real variable

const should have been the default in C++.
Like this :

int i = 5 ; // i is a constant

var int i = 5 ; // i is a real variable
是伱的 2024-07-12 01:27:26

1.根据我的评估,最佳答案:

@Adisak的答案 是根据我的评估的最佳答案。 请注意,这个答案在一定程度上是最好的,因为它也是最有真实代码示例支持的除了使用声音和良好 -经过深思熟虑的逻辑。

2. 我自己的话(同意最佳答案):

  1. 对于按值传递,添加 const 没有任何好处。 它所做的只是:
    1. 限制实现者每次想要更改源代码中的输入参数时都必须制作副本(无论如何,这种更改不会产生副作用,因为传入的内容已经是副本,因为它是按值传递的) 。 通常,更改按值传递的输入参数用于实现该函数,因此在各处添加 const 可能会阻碍这一点。
    2. 添加 const 会不必要地使代码变得混乱,到处都是 const,从而将注意力从真正需要安全的 const 上转移开。代码。
  2. 然而,在处理指针引用时,const在需要时至关重要,并且必须使用,因为它可以防止函数外部持续更改带来的不良副作用,因此当参数仅作为输入时,每个指针或引用都必须使用 const ,不是输出。 const 对通过引用或指针传递的参数使用具有额外的好处,可以使哪些参数是指针或引用非常明显。 需要强调的是,“小心!任何旁边有 const 的参数都是引用或指针!”。
  3. 我上面描述的内容通常是我工作过的专业软件组织中达成的共识,并且被认为是最佳实践。 有时,规则甚至很严格:“永远不要在按值传递的参数上使用 const,但如果它们只是输入,则始终在按引用或指针传递的参数上使用它。”

3 Google 的话(同意我的观点和最佳答案):(

来自“Google C++ 风格指南")

对于按值传递的函数参数,const 对调用者没有影响,因此不建议在函数声明中使用。 请参阅TotW #109

既不鼓励也不阻止在局部变量上使用 const。

资料来源:Google C++ 风格指南的“Const 的使用”部分:https://google .github.io/styleguide/cppguide.html#Use_of_const。 这实际上是一个非常有价值的部分,所以请阅读整个部分。

请注意,“TotW #109”代表 “本周提示 #109:有意义的 const函数声明”,也是一本有用的读物​​。 它提供的信息更多,对要做什么的规定较少,并且基于上下文,早于上面引用的关于 const 的 Google C++ 样式指南规则,但由于它提供了清晰度,上面引用的 const 规则已添加到 Google C++ 样式指南中。

另请注意,尽管我在这里引用 Google C++ 样式指南来捍卫我的立场,但这并不意味着我始终遵循该指南或始终建议遵循该指南。 他们推荐的一些东西实在是太奇怪了,例如他们的kDaysInAWeek“常量名称”风格的命名约定但是,指出世界上最成功和最有影响力的技术和软件公司之一使用与我和@Adisak等其他人相同的理由来支持我们对此事的观点仍然是有用和相关的。< /em>

4. Clang 的 linter clang-tidy 对此有一些选项:

A. 还值得注意的是,Clang 的 linter clang-tidy 有一个选项, readability-avoid-const-params-in-decls此处描述,以支持在代码库中强制执行使用const进行传递-值函数参数:

检查函数声明是否具有顶级常量参数。

声明中的 const 值不会影响函数的签名,因此不应将它们放在那里。

示例:

void f(const string);   // 不好:const 是顶层。 
  void f(const string&);   // 好:const 不是顶级的。 
  

为了完整和清晰起见,我自己添加了另外两个示例:

void f(char * const c_string);   // Bad: const is top level. [This makes the _pointer itself_, NOT what it points to, const]
void f(const char * c_string);   // Good: const is not top level. [This makes what is being _pointed to_ const]

B.它还有此选项:readability-const-return-type - https://clang.llvm.org/extra/clang-tidy/checks/readability-const- return-type.html

5. 我对此事如何编写风格指南的务实方法:

我只需将其复制并粘贴到我的风格指南中:

[复制/粘贴开始]

  1. 始终当函数参数的内容(它们指向的内容)不希望被更改时,请在通过引用或指针传递的函数参数上使用 const。 这样,当通过引用或指针传递的变量需要更改时就会变得很明显,因为它将缺少 const。 在此用例中,const 可防止函数外部发生意外副作用。
  2. 不建议在按值传递的函数参数上使用 const,因为 const 对调用者没有影响:即使变量发生更改函数内不会有函数外的副作用。 请参阅以下资源以获取更多理由和见解:
    1. “Google C++ 风格指南”“const 的使用”部分
    2. “本周提示 #109:函数声明中有意义的 const
    3. Adisak 在 Stack Overflow 上关于“使用‘const’表示函数”的回答参数”
  3. 切勿在以下声明中的函数参数上使用顶级 const [即:按值传递的参数上的 const]不是定义(并且注意不要复制/粘贴无意义的const)。它是没有意义的并且会被编译器忽略,它是视觉噪音,并且可能会误导读者”(< a href="https://abseil.io/tips/109" rel="noreferrer">https://abseil.io/tips/109,强调)。
  4. 唯一对编译有影响的 const 限定符是那些放置在函数定义中的限定符,而不是那些放置在函数的前向声明中的限定符,例如头文件中的函数(方法)声明中的限定符。
  5. 永远不要在返回的值上使用顶级const [即:按值传递的变量上的const] 通过一个函数。
  6. 在函数返回的指针或引用上使用const由实现者决定,因为它有时很有用。
  7. TODO:使用以下 clang-tidy 选项强制执行上述部分内容:
  8. https://clang.llvm.org/extra/clang-tidy/checks/readability-avoid-const-params-in-decls.html
  9. https://clang.llvm.org/extra /clang-tidy/checks/readability-const-return-type.html

以下是一些代码示例,用于演示上述 const 规则:

const 参数示例:
(有些是从这里借来的< /a>)

void f(const std::string);   // Bad: const is top level.
void f(const std::string&);  // Good: const is not top level.

void f(char * const c_string);   // Bad: const is top level. [This makes the _pointer itself_, NOT what it points to, const]
void f(const char * c_string);   // Good: const is not top level. [This makes what is being _pointed to_ const]

const 返回类型示例:
(有些是从此处借用的)

// BAD--do not do this:
const int foo();
const Clazz foo();
Clazz *const foo();

// OK--up to the implementer:
const int* foo();
const int& foo();
const Clazz* foo();

[COPY/PASTE END]

关键字:函数参数中使用const; 编码标准; C 和 C++ 编码标准; 编码指南; 最佳实践; 代码标准; 常量返回值

1. Best answer based on my assessment:

The answer by @Adisak is the best answer here based on my assessment. Note that this answer is in part the best because it is also the most well-backed-up with real code examples, in addition to using sound and well-thought-out logic.

2. My own words (agreeing with the best answer):

  1. For pass-by-value there is no benefit to adding const. All it does is:
    1. limit the implementer to have to make a copy every time they want to change an input param in the source code (which change would have no side effects anyway since what's passed in is already a copy since it's pass-by-value). And frequently, changing an input param which is passed by value is used to implement the function, so adding const everywhere can hinder this.
    2. and adding const unnecessarily clutters the code with consts everywhere, drawing attention away from the consts that are truly necessary to have safe code.
  2. When dealing with pointers or references, however, const is critically important when needed, and must be used, as it prevents undesired side effects with persistent changes outside the function, and therefore every single pointer or reference must use const when the param is an input only, not an output. Using const only on parameters passed by reference or pointer has the additional benefit of making it really obvious which parameters are pointers or references. It's one more thing to stick out and say "Watch out! Any param with const next to it is a reference or pointer!".
  3. What I've described above has frequently been the consensus achieved in professional software organizations I have worked in, and has been considered best practice. Sometimes even, the rule has been strict: "don't ever use const on parameters which are passed by value, but always use it on parameters passed by reference or pointer if they are inputs only."

3. Google's words (agreeing with me and the best answer):

(From the "Google C++ Style Guide")

For a function parameter passed by value, const has no effect on the caller, thus is not recommended in function declarations. See TotW #109.

Using const on local variables is neither encouraged nor discouraged.

Source: the "Use of const" section of the Google C++ Style Guide: https://google.github.io/styleguide/cppguide.html#Use_of_const. This is actually a really valuable section, so read the whole section.

Note that "TotW #109" stands for "Tip of the Week #109: Meaningful const in Function Declarations", and is also a useful read. It is more informative and less prescriptive on what to do, and based on context came before the Google C++ Style Guide rule on const quoted just above, but as a result of the clarity it provided, the const rule quoted just above was added to the Google C++ Style Guide.

Also note that even though I'm quoting the Google C++ Style Guide here in defense of my position, it does NOT mean I always follow the guide or always recommend following the guide. Some of the things they recommend are just plain weird, such as their kDaysInAWeek-style naming convention for "Constant Names". However, it is still nonetheless useful and relevant to point out when one of the world's most successful and influential technical and software companies uses the same justification as I and others like @Adisak do to back up our viewpoints on this matter.

4. Clang's linter, clang-tidy, has some options for this:

A. It's also worth noting that Clang's linter, clang-tidy, has an option, readability-avoid-const-params-in-decls, described here, to support enforcing in a code base not using const for pass-by-value function parameters:

Checks whether a function declaration has parameters that are top level const.

const values in declarations do not affect the signature of a function, so they should not be put there.

Examples:

void f(const string);   // Bad: const is top level.
void f(const string&);  // Good: const is not top level.

And here are two more examples I'm adding myself for completeness and clarity:

void f(char * const c_string);   // Bad: const is top level. [This makes the _pointer itself_, NOT what it points to, const]
void f(const char * c_string);   // Good: const is not top level. [This makes what is being _pointed to_ const]

B. It also has this option: readability-const-return-type - https://clang.llvm.org/extra/clang-tidy/checks/readability-const-return-type.html

5. My pragmatic approach to how I'd word a style guide on the matter:

I'd simply copy and paste this into my style guide:

[COPY/PASTE START]

  1. Always use const on function parameters passed by reference or pointer when their contents (what they point to) are intended NOT to be changed. This way, it becomes obvious when a variable passed by reference or pointer IS expected to be changed, because it will lack const. In this use case const prevents accidental side effects outside the function.
  2. It is not recommended to use const on function parameters passed by value, because const has no effect on the caller: even if the variable is changed in the function there will be no side effects outside the function. See the following resources for additional justification and insight:
    1. "Google C++ Style Guide" "Use of const" section
    2. "Tip of the Week #109: Meaningful const in Function Declarations"
    3. Adisak's Stack Overflow answer on "Use of 'const' for function parameters"
  3. "Never use top-level const [ie: const on parameters passed by value] on function parameters in declarations that are not definitions (and be careful not to copy/paste a meaningless const). It is meaningless and ignored by the compiler, it is visual noise, and it could mislead readers" (https://abseil.io/tips/109, emphasis added).
  4. The only const qualifiers that have an effect on compilation are those placed in the function definition, NOT those in a forward declaration of the function, such as in a function (method) declaration in a header file.
  5. Never use top-level const [ie: const on variables passed by value] on values returned by a function.
  6. Using const on pointers or references returned by a function is up to the implementer, as it is sometimes useful.
  7. TODO: enforce some of the above with the following clang-tidy options:
  8. https://clang.llvm.org/extra/clang-tidy/checks/readability-avoid-const-params-in-decls.html
  9. https://clang.llvm.org/extra/clang-tidy/checks/readability-const-return-type.html

Here are some code examples to demonstrate the const rules described above:

const Parameter Examples:
(some are borrowed from here)

void f(const std::string);   // Bad: const is top level.
void f(const std::string&);  // Good: const is not top level.

void f(char * const c_string);   // Bad: const is top level. [This makes the _pointer itself_, NOT what it points to, const]
void f(const char * c_string);   // Good: const is not top level. [This makes what is being _pointed to_ const]

const Return Type Examples:
(some are borrowed from here)

// BAD--do not do this:
const int foo();
const Clazz foo();
Clazz *const foo();

// OK--up to the implementer:
const int* foo();
const int& foo();
const Clazz* foo();

[COPY/PASTE END]

Keywords: use of const in function parameters; coding standards; C and C++ coding standards; coding guidelines; best practices; code standards; const return values

故人爱我别走 2024-07-12 01:27:26

下面两行在功能上是等价的:

int foo (int a);
int foo (const int a);

显然,如果以第二种方式定义的话,你将无法修改 foo 主体中的 a,但与外部。

const 真正派上用场的是引用或指针参数:

int foo (const BigStruct &a);
int foo (const BigStruct *a);

这说明 foo 可以接受一个大参数,也许是一个千兆字节大小的数据结构,而不复制它。 此外,它还对调用者说:“Foo 不会*更改该参数的内容。” 传递 const 引用还允许编译器做出某些性能决策。

*:除非它抛弃了常量,但那是另一篇文章了。

The following two lines are functionally equivalent:

int foo (int a);
int foo (const int a);

Obviously you won't be able to modify a in the body of foo if it's defined the second way, but there's no difference from the outside.

Where const really comes in handy is with reference or pointer parameters:

int foo (const BigStruct &a);
int foo (const BigStruct *a);

What this says is that foo can take a large parameter, perhaps a data structure that's gigabytes in size, without copying it. Also, it says to the caller, "Foo won't* change the contents of that parameter." Passing a const reference also allows the compiler to make certain performance decisions.

*: Unless it casts away the const-ness, but that's another post.

痴情换悲伤 2024-07-12 01:27:26

const 当参数按值传递时毫无意义,因为您将
不修改调用者的对象。

错误。

这是关于自我记录你的代码和你的假设。

如果您的代码有很多人在处理,并且您的函数非常重要,那么您应该标记 const 任何可以标记的内容。 在编写工业强度的代码时,您应该始终假设您的同事都是精神病患者,试图以任何方式让您陷入困境(特别是因为将来通常是您自己)。

此外,正如前面有人提到的,它可能可以帮助编译器优化一些东西(尽管可能性不大)。

const is pointless when the argument is passed by value since you will
not be modifying the caller's object.

Wrong.

It's about self-documenting your code and your assumptions.

If your code has many people working on it and your functions are non-trivial then you should mark const any and everything that you can. When writing industrial-strength code, you should always assume that your coworkers are psychopaths trying to get you any way they can (especially since it's often yourself in the future).

Besides, as somebody mentioned earlier, it might help the compiler optimize things a bit (though it's a long shot).

苹果你个爱泡泡 2024-07-12 01:27:26

原因是参数的 const 仅适用于函数内部,因为它正在处理数据的副本。 这意味着函数签名实际上是相同的。 不过,经常这样做可能是不好的风格。

我个人倾向于不使用 const,除了引用和指针参数。 对于复制的对象来说,这并不重要,尽管它可以更安全,因为它表明了函数内的意图。 这确实是一个判断力。 尽管在循环某些内容时我确实倾向于使用 const_iterator 并且我不打算修改它,所以我想每个人都有自己的想法,只要 const 正确性供参考类型得到严格维护。

The reason is that const for the parameter only applies locally within the function, since it is working on a copy of the data. This means the function signature is really the same anyways. It's probably bad style to do this a lot though.

I personally tend to not use const except for reference and pointer parameters. For copied objects it doesn't really matter, although it can be safer as it signals intent within the function. It's really a judgement call. I do tend to use const_iterator though when looping on something and I don't intend on modifying it, so I guess to each his own, as long as const correctness for reference types is rigorously maintained.

茶色山野 2024-07-12 01:27:26

有时(太频繁了!)我必须整理别人的 C++ 代码。 我们都知道,别人的 C++ 代码几乎从定义上来说就是一团糟:) 因此,我破译本地数据流的第一件事就是在每个变量定义中放入 const直到编译器开始咆哮。 这也意味着 const 限定值参数,因为它们只是由调用者初始化的精美局部变量。

啊,我希望变量默认是 const ,并且非 const 变量需要 mutable :)

Sometimes (too often!) I have to untangle someone else's C++ code. And we all know that someone else's C++ code is a complete mess almost by definition :) So the first thing I do to decipher local data flow is put const in every variable definition until compiler starts barking. This means const-qualifying value arguments as well, because they are just fancy local variables initialized by caller.

Ah, I wish variables were const by default and mutable was required for non-const variables :)

青柠芒果 2024-07-12 01:27:26

从 API 的角度来看,额外的多余 const 是不好的:

在代码中为按值传递的内部类型参数放置额外的多余 const 使 API 变得混乱,同时对调用者或 API 用户没有做出任何有意义的承诺(这只是妨碍了实施)。

API 中太多不需要的“const”就像“狼来了”,最终人们会开始忽略“const”,因为它无处不在,而且大多数时候没有任何意义。

API 中额外 const 的“reductio adabsurdum”参数对于前两点是有好处的,如果更多 const 参数是好的,那么每个可以有 const 的参数都应该有一个 const。 事实上,如果它真的那么好,您会希望 const 成为参数的默认值,并且仅当您想要更改参数时才使用“mutable”之类的关键字。

因此,让我们尝试在任何可能的地方放入 const:

void mungerum(char * buffer, const char * mask, int count);

void mungerum(char * const buffer, const char * const mask, const int count);

考虑上面的代码行。 不仅声明更加混乱、更长、更难阅读,而且 API 用户可以安全地忽略四个“const”关键字中的三个。 然而,额外使用“const”使得第二行可能危险!

为什么?

快速误读第一个参数 char * const buffer 可能会让您认为它不会修改传入的数据缓冲区中的内存 - 然而,事实并非如此! 当快速浏览或误读时,多余的“const”可能会导致对您的 API 做出危险且不正确的假设


从代码实现的角度来看,多余的 const 也是不好的:

#if FLEXIBLE_IMPLEMENTATION
       #define SUPERFLUOUS_CONST
#else
       #define SUPERFLUOUS_CONST             const
#endif

void bytecopy(char * SUPERFLUOUS_CONST dest,
   const char *source, SUPERFLUOUS_CONST int count);

如果 FLEXIBLE_IMPLMENTATION 不为 true,则 API “承诺”不会按照下面的第一种方式实现该函数。

void bytecopy(char * SUPERFLUOUS_CONST dest,
   const char *source, SUPERFLUOUS_CONST int count)
{
       // Will break if !FLEXIBLE_IMPLEMENTATION
       while(count--)
       {
              *dest++=*source++;
       }
}

void bytecopy(char * SUPERFLUOUS_CONST dest,
   const char *source, SUPERFLUOUS_CONST int count)
{
       for(int i=0;i<count;i++)
       {
              dest[i]=source[i];
       }
}

这是一个非常愚蠢的承诺。 为什么你要做出一个对你的调用者没有任何好处并且只会限制你的实现的承诺呢?

这两个都是同一函数的完全有效的实现,因此您所做的一切都是不必要地把一只手绑在背后。

此外,这是一个非常肤浅的承诺,很容易(并且可以合法地规避)。

inline void bytecopyWrapped(char * dest,
   const char *source, int count)
{
       while(count--)
       {
              *dest++=*source++;
       }
}
void bytecopy(char * SUPERFLUOUS_CONST dest,
   const char *source,SUPERFLUOUS_CONST int count)
{
    bytecopyWrapped(dest, source, count);
}

看,我无论如何都以这种方式实现了它,尽管我承诺不这样做——只是使用包装函数。 这就像电影中坏人承诺不杀人,却命令他的追随者去杀掉他们一样。

那些多余的常量的价值不亚于电影坏人的承诺。


但说谎的能力变得更糟:

我发现你可以通过使用虚假 const 来使标头(声明)和代码(定义)中的 const 不匹配。 支持 const 的拥护者声称这是一件好事,因为它允许您仅在定义中添加 const。

// Example of const only in definition, not declaration
struct foo { void test(int *pi); };
void foo::test(int * const pi) { }

然而,反之亦然……您可以仅在声明中放置一个虚假常量,并在定义中忽略它。 这只会让 API 中多余的 const 变得更可怕,更可怕的谎言 - 请看这个例子:

struct foo
{
    void test(int * const pi);
};

void foo::test(int *pi) // Look, the const in the definition is so superfluous I can ignore it here
{
    pi++;  // I promised in my definition I wouldn't modify this
}

所有多余的 const 实际上所做的就是通过强迫实现者在需要时使用另一个本地副本或包装函数来降低实现者的代码的可读性。更改变量或通过非常量引用传递变量。

看这个例子。 哪个更具可读性? 很明显,第二个函数中额外变量的唯一原因是因为某些 API 设计者添加了多余的 const 吗?

struct llist
{
    llist * next;
};

void walkllist(llist *plist)
{
    llist *pnext;
    while(plist)
    {
        pnext=plist->next;
        walk(plist);
        plist=pnext;    // This line wouldn't compile if plist was const
    }
}

void walkllist(llist * SUPERFLUOUS_CONST plist)
{
    llist * pnotconst=plist;
    llist *pnext;
    while(pnotconst)
    {
        pnext=pnotconst->next;
        walk(pnotconst);
        pnotconst=pnext;
    }
}

希望我们在这里学到了一些东西。 多余的 const 是 API 混乱的碍眼者、烦人的唠叨者、肤浅而无意义的承诺、不必要的障碍,并且偶尔会导致非常危险的错误。

Extra Superfluous const are bad from an API stand-point:

Putting extra superfluous const's in your code for intrinsic type parameters passed by value clutters your API while making no meaningful promise to the caller or API user (it only hampers the implementation).

Too many 'const' in an API when not needed is like "crying wolf", eventually people will start ignoring 'const' because it's all over the place and means nothing most of the time.

The "reductio ad absurdum" argument to extra consts in API are good for these first two points would be is if more const parameters are good, then every argument that can have a const on it, SHOULD have a const on it. In fact, if it were truly that good, you'd want const to be the default for parameters and have a keyword like "mutable" only when you want to change the parameter.

So lets try putting in const whereever we can:

void mungerum(char * buffer, const char * mask, int count);

void mungerum(char * const buffer, const char * const mask, const int count);

Consider the line of code above. Not only is the declaration more cluttered and longer and harder to read but three of the four 'const' keywords can be safely ignored by the API user. However, the extra use of 'const' has made the second line potentially DANGEROUS!

Why?

A quick misread of the first parameter char * const buffer might make you think that it will not modify the memory in data buffer that is passed in -- however, this is not true! Superfluous 'const' can lead to dangerous and incorrect assumptions about your API when scanned or misread quickly.


Superfluous const are bad from a Code Implementation stand-point as well:

#if FLEXIBLE_IMPLEMENTATION
       #define SUPERFLUOUS_CONST
#else
       #define SUPERFLUOUS_CONST             const
#endif

void bytecopy(char * SUPERFLUOUS_CONST dest,
   const char *source, SUPERFLUOUS_CONST int count);

If FLEXIBLE_IMPLEMENTATION is not true, then the API is “promising” not to implement the function the first way below.

void bytecopy(char * SUPERFLUOUS_CONST dest,
   const char *source, SUPERFLUOUS_CONST int count)
{
       // Will break if !FLEXIBLE_IMPLEMENTATION
       while(count--)
       {
              *dest++=*source++;
       }
}

void bytecopy(char * SUPERFLUOUS_CONST dest,
   const char *source, SUPERFLUOUS_CONST int count)
{
       for(int i=0;i<count;i++)
       {
              dest[i]=source[i];
       }
}

That’s a very silly promise to make. Why should you make a promise that gives no benefit at all to your caller and only limits your implementation?

Both of these are perfectly valid implementations of the same function though so all you’ve done is tied one hand behind your back unnecessarily.

Furthermore, it’s a very shallow promise that is easily (and legally circumvented).

inline void bytecopyWrapped(char * dest,
   const char *source, int count)
{
       while(count--)
       {
              *dest++=*source++;
       }
}
void bytecopy(char * SUPERFLUOUS_CONST dest,
   const char *source,SUPERFLUOUS_CONST int count)
{
    bytecopyWrapped(dest, source, count);
}

Look, I implemented it that way anyhow even though I promised not to – just using a wrapper function. It’s like when the bad guy promises not to kill someone in a movie and orders his henchman to kill them instead.

Those superfluous const’s are worth no more than a promise from a movie bad-guy.


But the ability to lie gets even worse:

I have been enlightened that you can mismatch const in header (declaration) and code (definition) by using spurious const. The const-happy advocates claim this is a good thing since it lets you put const only in the definition.

// Example of const only in definition, not declaration
struct foo { void test(int *pi); };
void foo::test(int * const pi) { }

However, the converse is true... you can put a spurious const only in the declaration and ignore it in the definition. This only makes superfluous const in an API more of a terrible thing and a horrible lie - see this example:

struct foo
{
    void test(int * const pi);
};

void foo::test(int *pi) // Look, the const in the definition is so superfluous I can ignore it here
{
    pi++;  // I promised in my definition I wouldn't modify this
}

All the superfluous const actually does is make the implementer's code less readable by forcing him to use another local copy or a wrapper function when he wants to change the variable or pass the variable by non-const reference.

Look at this example. Which is more readable ? Is it obvious that the only reason for the extra variable in the second function is because some API designer threw in a superfluous const ?

struct llist
{
    llist * next;
};

void walkllist(llist *plist)
{
    llist *pnext;
    while(plist)
    {
        pnext=plist->next;
        walk(plist);
        plist=pnext;    // This line wouldn't compile if plist was const
    }
}

void walkllist(llist * SUPERFLUOUS_CONST plist)
{
    llist * pnotconst=plist;
    llist *pnext;
    while(pnotconst)
    {
        pnext=pnotconst->next;
        walk(pnotconst);
        pnotconst=pnext;
    }
}

Hopefully we've learned something here. Superfluous const is an API-cluttering eyesore, an annoying nag, a shallow and meaningless promise, an unnecessary hindrance, and occasionally leads to very dangerous mistakes.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文