我经常const
用于未修改的局部变量,如下所示:
const float height = person.getHeight();
我认为它可以使编译的代码可能更快,允许编译器进行更多优化。还是我错了,编译器可以自己弄清楚局部变量永远不会被修改?
我经常const
用于未修改的局部变量,如下所示:
const float height = person.getHeight();
我认为它可以使编译的代码可能更快,允许编译器进行更多优化。还是我错了,编译器可以自己弄清楚局部变量永远不会被修改?
还是我错了,编译器可以自己弄清楚局部变量永远不会被修改?
大多数编译器都很聪明,可以自己解决这个问题。
您应该使用const
确保const 正确性而不是微优化。
const 正确性让编译器可以帮助您防止犯诚实的错误,因此您应该const
尽可能使用,但出于可维护性的原因并防止自己犯下愚蠢的错误。
了解我们编写的代码对性能的影响是很好的,但应该避免过度的微优化。关于性能,一个应该遵循的,
通过对代表性数据集进行分析,确定使用资源
20%
的代码,然后才尝试优化这些瓶颈。80%
这种性能差异几乎可以肯定可以忽略不计,但是出于代码文档的原因,您应该尽可能使用 const。通常,编译器无论如何都可以为您解决这个问题并自动进行优化。const
实际上更多的是关于代码的可读性和清晰度而不是性能。
我认为默认情况下将包括函数参数在内的局部变量设为常量并不是一个好习惯。
主要原因是简洁。良好的编码实践可以让你的代码变短,而这个不行。
非常相似,您可以void foo(void)
在函数声明中编写,并且可以通过提高清晰度、明确不打算将参数传递给函数等来证明它的合理性,但这本质上是浪费空间,最终差点退出采用。const
我认为到处使用的趋势也会发生同样的事情。
对于大多数使用您创建的代码的协作者来说,使用 const 限定符标记局部变量并不是很有用。与类成员、全局变量或指针指向的数据不同,局部变量没有任何外部影响,没有人会受到局部变量限定符的限制或从中学到任何有用的东西(除非他将更改局部变量所在的特定函数)。
如果他需要更改您的功能,该任务通常不应该要求他尝试从那里的变量的常量限定符中推断出有价值的信息。函数不应太大或难以理解;如果是这样,您的设计可能有更严重的问题,请考虑重构。一个例外是实现一些核心数学计算的函数,但对于那些你需要在评论中添加一些细节或论文链接。
您可能会问,如果不花费您太多精力,为什么不仍然放置 const 限定符。不幸的是,确实如此。如果我必须放置所有 const 限定符,我很可能必须在完成后检查我的函数并将限定符放置到位 - 浪费时间。这样做的原因是您不必仔细计划局部变量的使用,这与指针指向的成员或数据不同。
它们主要是一种便利工具,从技术上讲,可以通过将它们分解为表达式或重用变量来避免它们中的大多数。因此,由于它们是一种方便的工具,特定局部变量的存在只是一个品味问题。
特别是,我可以写:
int d = foo(b) + c;
const int a = foo(b); int d = a + c;
int a = foo(b); a += c
每个变体在各个方面都是相同的,除了变量a
是恒定的还是非恒定的,或者根本不存在。很难尽早做出某些选择。
如果左侧有一个值类型,您可以放心地假设它的影响可以忽略不计,或者根本没有影响。它不会影响重载决议,实际上const
可以很容易地从范围中推断出来。
引用类型完全不同:
std::vector<int> v(1);
const auto& a = v[0];
auto& b = v[0];
这两个赋值解析为两个完全不同的运算符,并且在 STL 之外的许多库中也可以找到类似的重载对。即使在这个简单的例子中,依赖于v
范围不变的优化b
已经不再是微不足道的并且不太可能被发现。
尽管如此,STL 在这些方面仍然相当温和,至少行为不会因选择const_reference
重载而改变。对于大多数 STL,const_reference
重载仅与对象const
本身相关联。
其他一些库(例如 Qt)大量使用了写时复制语义。在这些 const-correctness 中,引用不再是可选的,而是必要的:
QVector<int> v1(1);
auto v2 = v1; // Backing storage of v2 and v1 is still linked
const auto& a = v1[0]; // Still linked
const auto& b = v2[0]; // Still linked
auto& c = v2[0]; // Deep copy from v1 to v2 is happening now :(
// Even worse, &b != &c
写时复制语义是大型矩阵或图像处理库中常见的东西,需要注意。
这也是编译器不再能够拯救你的地方,重载解决方案是 C++ 标准规定的,并且没有消除代价高昂的副作用的余地。
局部常量值存在一个主要问题——如下面的代码所示:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
// const uint32_t const_dummy = 0;
void func1(const uint32_t *ptr);
int main(void) {
const uint32_t const_dummy = 0;
func1(&const_dummy);
printf("0x%x\n", const_dummy);
return EXIT_SUCCESS;
}
void func1(const uint32_t *ptr) {
uint32_t *tmp = (uint32_t *)ptr;
*tmp = 1;
}
此代码是在 Ubuntu 18.04 上编译的。
如您所见,const_dummy
在这种情况下可以修改 ' 的值!但是,如果您修改代码并将const_dummy
范围设置为全局 - 通过注释掉本地定义并从全局定义中删除注释 - 您将收到异常并且您的程序将崩溃 - 这很好,因为您可以调试它并发现问题。
是什么原因?全局const
值位于程序的 ro(只读)部分。操作系统 - 使用 MMU 保护该区域。使用堆栈中定义的常量是不可能的。
对于不使用 MMU 的系统,您甚至不会“感觉”有问题。