我应该使用const作为局部变量来进行更好的代码优化吗?

时间:2012-05-25 02:56:54

标签: c++ performance optimization const compiler-optimization

我经常将const用于未修改的局部变量,如下所示:

const float height = person.getHeight();

我认为它可以使编译的代码更快,允许编译器进行更多优化。或者我错了,编译器可以自己弄清楚局部变量永远不会被修改?

5 个答案:

答案 0 :(得分:42)

  

或者我错了,编译器可以自己弄清楚局部变量永远不会被修改?

大多数编译器都很聪明,可以自己解决这个问题 您应该使用const来确保 const-correctness 而不是微优化。
const correctness 让编译器帮助您防止犯下诚实错误,因此您应尽可能使用const 可维护性原因 & 阻止自己做出愚蠢的错误

理解我们编写的代码的性能影响是很好的,但应避免过度的微优化。关于表现,应该遵循,

80-20规则:

  

确定使用20%资源的代码的80% 代表性数据集 通过概要分析 然后才尝试优化这些瓶颈。

答案 1 :(得分:11)

这种性能差异几乎肯定可以忽略不计,但是出于代码文档的原因,应尽可能使用const。很多时候,编译器无论如何都可以解决这个问题并自动进行优化。 const更多的是代码可读性和清晰度而非性能。

答案 2 :(得分:1)

我认为让局部变量(包括函数参数)默认为常量不是一个好习惯。

主要原因是简洁。好的编码习惯可以使您的代码简短,而事实并非如此。

同样,您可以在函数声明中编写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是常数还是不是常数,或者根本不存在之外,每个变体在各个方面都是相同的。很难尽早做出一些选择。

答案 3 :(得分:0)

如果左侧有 值类型 ,则可以放心地认为它的影响可以忽略不计,或者根本没有影响。它不会影响重载分辨率,实际上const可以很容易地从范围中推导出来。


引用类型 完全不同:

std::vector<int> v(1);
const auto& a = v[0];
auto& b = v[0];

这两个分配解析为两个完全不同的运算符,并且在STL之外的许多库中也发现了类似的重载对。即使在这个简单的示例中,依赖于vb范围内不变的优化也已不再是微不足道的,也不太可能被发现。

STL在这些方面还是很温和的,至少可以根据是否选择const_reference重载来改变行为。对于大多数STL,const_reference重载仅与对象本身就是const有关。

其他一些库(例如Qt)大量使用了写时复制语义。在这些带有引用的const正确性中,不再是可选的,而是必要的:

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 ++标准规定了重载解决方案,并且没有任何余地可以消除代价高昂的副作用。

答案 4 :(得分:-2)

本地常量值存在一个主要问题-如下代码所示:

#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的系统,您甚至不会“感觉”有问题。