指標常量#
int *const ptr = nullptr;
const
修飾的是指標 ptr
的值,ptr
本身不能被修改,所以指標常量必須初始化,同時我們無法對 ptr
的值進行修改。
int a = 10;
int *const ptr = &a;
ptr = nullptr; // 錯誤
指標常量的應用場景#
例如:需要編寫一個函數,實現使用傳參指標的形式交換兩個整數的值。
下面是實現代碼:
void swap(int *a, int *b) {
int tmp = *a;
*a = *b;
*b = tmp;
}
上述代碼可以實現功能,但是存在一定的問題,因為我們可以在函數體內可以修改指標的所指向的值,同時也可以修改指標的值(這並不是我們所希望的),為了使代碼更為健壯,我們可以使用指標常量,使得傳入指標的值不會被無意修改。
下面是修改後的代碼:
void swap(int *const a, int *const b) { ... }
常量指標#
const int *ptr;
// 或
int const *ptr;
const
修飾的 *ptr
的值,也就是指標所指向的值,ptr
指向的值是不可修改的。同時在不進行常量類型轉換的情況下我們無法對 *ptr
進行修改。
int a = 10;
int const *ptr = &a;
*ptr = 20; // 錯誤
常量指標的應用場景#
例如:需要編寫一個函數,實現打印一個數組。
下面是實現代碼:
void printArray(int const* arr, size_t len) {
for (size_t i = 0; i < len; ++i) {
std::cout << arr[i] << " ";
}
}
這裡你可能會認為使用 const
修飾數組退化而來的指標所指向的值就可以了,但是這仍存在的問題,因為我們仍可以在函數體內修改指標的值,這並不是我們希望的,因此在此基礎上還需要 const
修飾指標的值。
下面是修改後的代碼:
void printArray(int const *const arr, size_t len) { ... }
指標常量與常量指標的關係#
我們會發現常量指標有兩種寫法:int const *
和 const int *
。
對於第一種形式的理解:const
是向左修飾的,例如:int const *ptr;
中 const
修飾的是 int
值類型,所以指標指向的值不可以修改;int *const ptr = nullptr;
中 const
修飾 int *
指標類型,所以指標指向不能修改。這種理解需要遵守的代碼規範,因為如果將常量指標寫成 const int *
就需要我們進行轉換了。(也可以理解為如果左側沒有對象,則轉為修飾右側對象。)
常量指標和指標常量的命名則是與 const int *
和 int *const
的代碼規範相對應。
觀察以下代碼:
#include <iostream>
struct A {
void foo() { std::cout << "non const" << std::endl; }
void foo() const { std::cout << "const" << std::endl; }
};
int main() {
A a;
A *const ptr1 = &a;
ptr1->foo();
A const *ptr2 = &a;
ptr2->foo();
}
int *const ptr1 = &a
中 const
修飾的是 ptr1
指標的值,沒有修飾指標所指向的對象,所以 ptr1->foo()
調用非 const
版本。
int const *ptr2 = &a
中 const
修飾的是 ptr2
指標指向的值 a
,意思是指向的值不可修改,所以 ptr2->foo()
調用 const
版本。
如有紕漏,歡迎指正。