C ++:Const正确性和指针参数

时间:2012-01-10 18:05:38

标签: c++ function pointers const

我知道const指针可以通过几种方式声明:

const int * intPtr1; // Declares a pointer that cannot be changed.
int * const intPtr2; // Declares a pointer whose contents cannot be changed.

// EDIT: THE ABOVE CLAIMS ARE INCORRECT, PLEASE READ THE ANSWERS.

但是在函数参数的上下文中,相同的原理呢?

我认为以下是多余的:

void someFunc1(const int * arg);
void someFunc2(int * arg);

由于someFunc 1和2对指针本身执行pass-by-value,因此someFunc1在给定函数调用中不可能更改原始指针的值。举例说明:

int i = 5;
int * iPtr = &i;

someFunc1(iPtr); // The value of iPtr is copied in and thus cannot be changed by someFunc1.

如果这些都是真的,那么永远没有必要使用' const int * ptr'来声明一个函数。输入arg,对吗?

5 个答案:

答案 0 :(得分:30)

你倒退了:

const int * intPtr1; // Declares a pointer whose contents cannot be changed.
int * const intPtr2; // Declares a pointer that cannot be changed.

以下const确实是不必要的,并且没有理由将它放在函数声明中:

void someFunc1(int * const arg);

但是,您可能希望将其放在函数 implementation 中,原因与您可能希望声明局部变量(或其他任何内容)const的原因相同 - 实现可能当你知道某些事情不会改变时,你会更容易理解。无论是否在函数的任何其他声明中声明const,都可以这样做。

答案 1 :(得分:24)

它不适用于调用者,而是适用于someFunc1内的代码。因此someFunc1内的任何代码都不会意外地更改它。像

void someFunc1(int *arg) {
  int i = 9;
  arg = &i;  // here is the issue
  int j = *arg;
}

让我们做一些案例研究:

1)只需将指向值const

void someFunc1(const int * arg) {
int i = 9;
*arg = i; // <- compiler error as pointed value is const
}

2)只需使指针const

void someFunc1(int * const arg) {
int i = 9;
arg = &i; // <- compiler error as pointer is const
}

3)如果涉及的变量可以是const,则使用const的正确方法是:

void someFunc1(const int * const arg) {
    int i = 9;
    *arg = i; // <- compiler error as pointed value is const
    arg = &i; // <- compiler error as pointer is const
}

这应该清除所有的疑虑。所以我已经提到它是用于功能代码而不是用于调用者,你应该使用上面提到的3种情况中最严格的。

编辑:

  • 即使在函数声明中,声明const也是一种很好的做法。这不仅会提高可读性,而且调用者也会意识到合同,并且对参数的不变性更有信心。 (这是必需的bcoz你通常共享你的头文件,所以调用者可能没有你的实现c / cpp文件)
  • 如果声明和定义同步,甚至编译器也可以指出更好。

答案 2 :(得分:6)

你的逻辑错误。您应该向后阅读该类型,因此const int *是指向const int的指针,int * const是指向int的const指针。

示例:

void foo() {
    int a = 0;
    int b = 0;

    int * const ptrA = &a;
    *ptrA = 1;
    ptrA = &b; ///< Error

    const int * ptrB = &a;
    *ptrB = 1; ///< Error
    ptrB = &b;

    const int * const ptrC = &a;
    *ptrC = 1; ///< Error
    ptrC = &a; ///< Error
}

为了详细说明为什么你希望你的函数参数是const int *,你可能想要告诉调用者他们必须传入int,因为你作为一个函数想要改变它值。例如,请考虑以下代码:

void someFunc1(const int * arg) {
    // Can't change *arg in here
}

void someFunc2(int * arg) {
    *arg = 5;
}

void foo() {
    int a = 0;
    someFunc1(&a);
    someFunc2(&a);

    const int b = 0;
    someFunc1(&b);
    someFunc2(&b); ///< *** Error here. Must pass in an int not a const int.
}

答案 3 :(得分:2)

是的,你是对的(忽略了你错误地解决了这个问题) - 采用非参考const参数是没有意义的。此外,返回非参考const值没有任何意义。

答案 4 :(得分:2)

你有错误的方法:

const int * intPtr1; // Declares a pointer whose contents cannot be changed.
int * const intPtr2; // Declares a pointer that cannot be changed.

一般来说,在编写表达式略有不同时,更容易推理constness:const int*int const *的类型相同。在该表示法中,规则更清晰,const始终适用于其前面的类型,因此:

int const * intPtr1; // Declares a pointer to const int.
int * const intPtr2; // Declares a const pointer to int.
int const * * const * complexPtr; // A pointer to const pointer to pointer to const int

当使用前导const编写类型时,const的处理方式就像是在第一种类型之后编写的,因此const T*变为T const *

void someFunc2(int * arg);

因此不是多余的,因为someFunc2可能会更改arg的内容,而someFunc1可能不会。 void someFunc3(int * const arg);虽然是

,但仍然是多余的(而且是暧昧的)