33

我知道几乎没有关于 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
}
4

6 回答 6

14

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

但是,我发现它有时对我有帮助,因为它可以检查我的实现没有做我不打算做的事情(如问题末尾的示例所示)。

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

例如,我可能正在实现一个 C 函数,它接受几个指向缓冲区的指针——一个指向开始的指针,一个指向结束的指针。我打算将数据放入缓冲区,但要确保不会超出末尾。所以在函数内部有代码会在我向它添加数据时增加一个指针。将指向缓冲区末尾的指针作为const参数将确保我不会编写一个错误,该错误会意外地增加结束边界指针而不是我真正应该增加的指针。

所以一个带有这样签名的 fillArray 函数:

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

pEnd当我真的想增加时,会阻止我意外增加pStart。这不是什么大事,但我很确定每个用 C 语言编程过一段时间的人都遇到过这样的错误。

于 2009-11-12T17:54:53.603 回答
13

我的看法:

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

在您的问题中,您提供了一个很好的示例,说明何时可能会捕获错误,但有时您最终也会执行以下操作:

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

   /* … */
}

无论哪种方式,利弊都是次要的。

于 2009-11-12T17:58:16.277 回答
1

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

于 2009-11-12T18:00:20.470 回答
0

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

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

我可能不这样做的一个原因是 value 参数的 const-ness 是您的客户不需要知道的实现细节。如果您稍后(故意)更改您的函数,以便它确实更改了该值,您将需要更改函数的签名,这将迫使您的客户端重新编译。

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

于 2009-11-12T18:50:12.770 回答
0

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

不能修改 const 对象

但是改变'*i'(即*i = 3;)意味着你没有改变'i'的值,而是'i'指向的地址的值

实际上,const 函数适用于不应被函数更改的大型对象。

于 2016-04-12T14:39:04.867 回答
-2

我喜欢这种情况下的 const 正确性:
void foo(const Bar &b) //I know b cannot be changed
{
//do something with b
}

这让我可以使用b而不必担心修改它,而且我不必支付复制构造函数的成本。

于 2009-11-12T18:02:25.660 回答