const 基本数据类型
了解 const 原始数据类型参数。
让我们探讨在函数参数列表中使用 const 参数的时机。我们需要区分基本类型(也称为原始数据类型)和类类型。
引言
本节讨论的是基本类型,例如 bool、int、float、char 等。
这类参数是否应该以 const 方式传递?
答案是否定的,因为这样做效率低下。如果按值传递,我们可以仅通过一次内存读取访问这些数据类型。而如果通过引用或指针传递,则需要先读取变量地址,再解引用获取值,这相当于两次内存读取,效率更低。
因此,我们不应将基本类型通过 const& 传递。
但是否应该简单地以 const 方式传递?
如果不需要修改参数的值,那么我们应该这么做!这有助于提高代码可读性,对编译器友好,并为未来维护提供保障。
1void setFoo(const int foo) { 2 this->m_foo = foo; 3}
虽然看起来有些过度严谨,但并不会带来负面影响。这种方式明确表达了意图,我们无法预知未来方法是否会扩展,比如增加额外检查或异常处理逻辑。
如果参数未标记为 const,而其值被意外修改,可能会导致难以察觉的错误。
一旦将 foo 声明为 const,这种场景就不可能发生。
若将来确实需要修改该参数的值,就必须移除 const 限定符,但这将是刻意为之的操作。在代码审查中,这样的改动会显得显眼,尤其当 PR 内容简洁时更为突出。
反之,如果确实需要修改参数,就不应将其声明为 const。
不应使用 const 参数的情况
有时我们会看到如下写法:
如果需要拷贝参数,就不应将其声明为 const。
1void doSomething(const int foo) { 2 // ... 3 int foo2 = foo; 4 foo2++; 5 // ... 6 }
如果我们计划修改参数值,就没有必要将其设为 const。这样只会多出一个栈上的无用变量,以及一次无意义的赋值操作。直接按值传递即可。
需要修改参数时的非 const 传递
如果计划修改参数值,应将其声明为非 const 的值参数。
1void doSomething(int foo) { 2 // ... 3 foo++; 4 // ... 5}
简而言之:我们不会将基本类型通过 const& 或 const T* 传递。只有在不打算修改参数时,才使用 const T 传递。