值参数的常量正确性

发布于 2024-08-11 19:03:37 字数 1516 浏览 11 评论 0原文

我知道关于 const 正确性的问题很少,其中指出函数的声明及其定义不需要就值参数达成一致。这是因为值参数的常量仅在函数内部重要。这很好:

// header
int func(int i);

// cpp
int func(const int i) {
    return i;
}

这样做真的是最佳实践吗?因为我从来没有见过有人这么做过。我在其他地方看到过这句话(不确定来源):

“事实上,对于编译器来说,无论是否在值参数前面包含此 const,函数签名都是相同的。”

“避免在函数声明中使用 const 传值参数。如果不被修改,仍将参数设置为 const 在同一函数的定义中。”

第二段说不要将 const 放在声明中。我认为这是因为值参数的常量作为接口定义的一部分是没有意义的。这是一个实施细节。

基于这个建议,对于指针参数的指针值是否也有建议? (它对引用参数没有意义,因为您无法重新分配引用。)

// header
int func1(int* i);
int func2(int* i);

// cpp
int func1(int* i) {
    int x = 0;

    *i = 3; // compiles without error
    i = &x; // compiles without error

    return *i;
}
int func2(int* const i) {
    int x = 0;

    *i = 3; // compiles without error
    i = &x; // compile error

    return *i;
}

摘要: 创建值参数对于捕获一些逻辑错误很有用。这是最佳实践吗?您是否会极端地将 const 排除在头文件之外?它与 const 指针值一样有用吗?为什么或为什么不呢?

一些参考资料:

C++ const 关键字 - 自由使用? 对函数参数使用“const”

const 值参数的示例有用:

bool are_ints_equal(const int i, const int j) {
    if (i = j) { // without the consts this would compile without error
        return true;
    } else {
        return false;
    }
    // return i = j; // I know it can be shortened
}

I know there are few question about const correctness where it is stated that the declaration of a function and its definition do not need to agree for value parameters. This is because the constness of a value parameter only matters inside the function. This is fine:

// header
int func(int i);

// cpp
int func(const int i) {
    return i;
}

Is doing this really a best practice? Because I've never seen anyone do it. I've seen this quotation (not sure of the source) in other places this has been discussed:

"In fact, to the compiler, the function signature is the same whether you include this const in front of a value parameter or not."

"Avoid const pass-by-value parameters in function declarations. Still make the parameter const in the same function's definition if it won't be modified."

The second paragraph says to not put the const in the declaration. I assume this is because the constness of a value parameter is meaningless as part of a interface definition. It is an implementation detail.

Based on this recommendation, is it also recommended for the pointer values of pointer parameters? (It is meaningless on a reference parameter since you can't reassign a reference.)

// header
int func1(int* i);
int func2(int* i);

// cpp
int func1(int* i) {
    int x = 0;

    *i = 3; // compiles without error
    i = &x; // compiles without error

    return *i;
}
int func2(int* const i) {
    int x = 0;

    *i = 3; // compiles without error
    i = &x; // compile error

    return *i;
}

Summary: Making value parameters is useful to catch some logic errors. Is it a best practice? Do you go to the extreme of leaving the const out of the header file? Is it just as useful to const pointer values? Why or why not?

Some references:

C++ const keyword - use liberally?
Use of 'const' for function parameters

An example of when const value parameters are useful:

bool are_ints_equal(const int i, const int j) {
    if (i = j) { // without the consts this would compile without error
        return true;
    } else {
        return false;
    }
    // return i = j; // I know it can be shortened
}

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

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

发布评论

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

评论(6

萌无敌 2024-08-18 19:03:37

我的看法:

这不是一个坏主意,但问题很小,你的精力最好花在其他事情上。

在您的问题中,您提供了一个很好的例子,说明何时可能会捕获错误,但有时您最终也会做这样的事情:

void foo(const int count /* … */)
{
   int temp = count;  // can't modify count, so we need a copy of it
   ++temp;

   /* … */
}

无论哪种方式,优点和缺点都很小。

My take on it:

It's not a bad idea, but the issue is minor and your energy might be better spent on other things.

In your question you provided a good example of when it might catch an error, but occasionally you also end up doing something like this:

void foo(const int count /* … */)
{
   int temp = count;  // can't modify count, so we need a copy of it
   ++temp;

   /* … */
}

The pros and cons are minor either way.

宁愿没拥抱 2024-08-18 19:03:37

我多次读到,在函数中将值参数设置为 const 是一件坏事,因为它是不必要的。

但是,我发现它有时对我有帮助,可以检查我的实现是否不会执行我不打算执行的操作(如问题末尾的示例所示)。

因此,虽然它可能不会为调用者增加价值,但有时它确实为我作为实现者增加了一点价值,并且它不会从调用者那里夺走任何东西。所以我认为使用它没有什么坏处。

例如,我可能正在实现一个 C 函数,它接受两个指向缓冲区的指针 - 一个指向开始的指针,一个指向结束的指针。我将把数据放入缓冲区,但想确保不会超出末尾。因此,在函数内部,有一些代码会在我向指针添加数据时递增指针。将指向缓冲区末尾的指针设置为 const 参数将确保我不会编写出意外增加结束边界指针而不是我真正应该增加的指针的错误。

因此,具有如下签名的 fillArray 函数

size_t fillArray( data_t* pStart, data_t* const pEnd);

将防止我在真正想要增加 pStart 时意外地增加 pEnd。这不是什么大问题,但我很确定每个用 C 编程一段时间的人都遇到过这样的错误。

I've read many times that making value parameters in a function const is a bad thing to do because it's unnecessary.

However, I find it occasionally helpful to me as a check that my implementation doesn't do something I don't intend (as in the example at the end of your question).

So, while it may not add value to the caller, it does sometimes add a small bit of value to me as an implementer, and it doesn't take anything away from the caller. So I see no harm using it.

For example, I may be implementing a C function that takes a couple pointers to a buffer - a pointer to the start, and a pointer to the end. I'm going to put data in the buffer, but want to ensure that I don't overrun the end. So inside the function there's code that will increment a pointer as I'm adding data to it. Making the pointer to the end of the buffer a const parameter will ensure that I don't code up a bug that accidentally increments the end boundary pointer instead of the pointer I really should be incrementing.

So a fillArray function with a signature like this:

size_t fillArray( data_t* pStart, data_t* const pEnd);

will prevent me from accidentally incrementing pEnd when I really mean to increment pStart. It's not a huge thing, but I'm pretty sure everyone who has programmed for any period of time in C has run across such a bug.

晚风撩人 2024-08-18 19:03:37

不幸的是,一些编译器(我正在看你,Sun CC!)错误地区分声明为 const 的参数和未声明为 const 的参数,并且您可能会收到有关未定义函数的错误。

Unfortunately, some compilers (I'm looking at you, Sun CC!) incorrectly differentiate between arguments declared const and ones not declared so, and you can get errors about undefined functions.

青巷忧颜 2024-08-18 19:03:37

我认为这取决于你的个人风格。

它不会增加或减少客户端可以传递给您的函数的内容。本质上它就像一个编译时断言。如果它可以帮助你知道价值不会改变,那就继续做吧,但我不认为其他人这样做有什么重要理由。

我可能不这样做的原因之一是值参数的常量性是您的客户不需要了解的实现细节。如果您稍后(故意)更改函数以使其实际上更改该值,则您将需要更改函数的签名,这将迫使您的客户端重新编译。

这类似于为什么有些人建议不要使用公共虚拟方法(函数虚拟性是应该对客户端隐藏的实现细节),但我不属于那个特定阵营。

I think this is dependent on your personal style.

It doesn't add or subtract to what clients can pass to your function. In essence it's like a compile-time assertion. If it helps you to know that value won't change, go ahead and do it, but I don't see a big reason for others to do it.

One reason I might not do it is that the const-ness of the value parameter is an implementation detail that your clients don't need to know about. If you later (purposely) change your function so that it actually does change that value, you will need to change the signature of your function, which will force your clients to re-compile.

This is similar to why some people recommend having no public virtual methods (the functions virtual-ness is an implementation detail that should be hidden from clients), but I'm not in that particular camp.

〆一缕阳光ご 2024-08-18 19:03:37

如果存在 const 关键字;这意味着'i'(const类型)的值不能被修改。
如果 'i' 的值在 foo 函数内更改,编译器将抛出错误:“

无法修改 const 对象

,但更改 '*i' (即 *i = 3;)意味着您不是更改 'i' 的值,而是更改 'i' 指向的地址的值

实际上,const 函数适用于应该不被功能改变。

If there is const keyword present; it means value of 'i' (which is const type) can not be modified.
If value of 'i' is changed inside foo function compiler will throw error: "

Can not modify const object

But changing '*i' (i.e. *i = 3;)means you are not changing value of 'i' but value of address pointed by 'i'

Actually,the const function is appropriate for large objects that should not be altered by function.

晨与橙与城 2024-08-18 19:03:37

我喜欢在这样的情况下使用 const 正确性:
void foo(const Bar &b) //我知道b不能改变
{
//用b做一些事情
这让我可以使用 b

不必担心修改它,但我不必支付复制构造函数的成本。

I like const correctness for situations like this:
void foo(const Bar &b) //I know b cannot be changed
{
//do something with b
}

This lets me use b without fear of modifying it, but I don't have to pay the cost of a copy constructor.

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