簡體   English   中英

我應該對局部變量使用 const 以獲得更好的代碼優化嗎?

[英]Should I use const for local variables for better code optimization?

我經常將const用於未被修改的局部變量,如下所示:

const float height = person.getHeight();

我認為它可以使編譯后的代碼可能更快,允許編譯器做更多的優化。 或者我錯了,編譯器可以自己弄清楚局部變量永遠不會被修改?

或者我錯了,編譯器可以自己弄清楚局部變量永遠不會被修改?

大多數編譯器都足夠聰明,可以自己解決這個問題。
您應該使用const來確保const 的正確性,而不是用於微優化。
const 正確性讓編譯器可以幫助您防止犯下誠實的錯誤,因此您應該盡可能使用const但出於可維護性的原因防止自己犯愚蠢的錯誤

理解我們編寫的代碼對性能的影響是很好的,但應該避免過度的微優化。 關於性能,應該遵循,

80-20 規則:

通過代表性數據集的分析,確定使用80%資源的20%代碼,然后嘗試優化這些瓶頸。

這種性能差異幾乎可以忽略不計,但是出於代碼文檔的原因,您應該盡可能使用 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 之外的許多庫中也可以找到類似的重載對。 即使在這個簡單的例子中,依賴於vb的范圍內不可變的優化已經不再是微不足道的,也不太可能被發現。

盡管如此,STL 在這些方面仍然相當溫和,至少行為不會根據是否選擇const_reference重載而改變。 對於大多數 STL, const_reference重載僅與作為const本身的對象相關聯。

其他一些庫(例如 Qt)大量使用了寫時復制語義。 在這些常量正確性中,引用不再是可選的,而是必要的:

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 的系統 - 您甚至不會“感覺”有問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM