簡體   English   中英

有什么理由不使用auto和C ++基於范圍的for循環?

[英]Any reason to not use auto& for C++ range-based for-loops?

例如,循環:

std::vector<int> vec;
...
for (auto& c : vec) { ... }

將迭代vec並通過引用復制每個元素。

有沒有理由這樣做?

for (int& c : vec) { ... }

這兩個代碼片段將生成相同的代碼:使用auto ,編譯器會發現底層類型是int ,並且執行完全相同的操作。

但是,使用auto的選項更具“面向未來”:如果稍后您決定使用uint8_t替換int以節省空間,則無需查看代碼以查找對可能需要更改的基礎類型,因為編譯器會自動為您執行此操作。

使用auto可以使代碼更好,但不管其他地方。 了解使用auto過度自由對可維護性的影響。

這里的問題真的是,如果有任何理由你不應該使用auto來做任何事情。

好吧,首先讓我們先解決一件事。 auto首次引入的根本原因是雙重的。

首先,它使復雜類型變量的聲明更簡單,更易於閱讀和理解。 for循環中聲明迭代器時尤其如此。 考慮C ++ 03 psudocode:

for (std::vector <Foo>::const_iterator it = myFoos.begin(); it != myFoos.end(); ++it)

隨着myFoos類型的復雜性變得更加復雜,這會變得更加復雜。 此外,如果myFoos的類型以微妙的方式改變,但是以一種對剛剛編寫的循環myFoos的方式,必須重新訪問復雜的聲明。 這是C ++ 11中更簡單的維護問題:

for (auto it = myFoos.begin(); it != myFoos.end(); ++it)

第二,有其產生是不可能處理不提供的設施的情況下auto和它的兄弟姐妹, decltype 這出現在模板中。 考慮( 來源 ):

template<typename T, typename S>
void foo(T lhs, S rhs) {
  auto prod = lhs * rhs;
  //...
}

在C ++ 03中,如果lhsrhs的類型不相同,則不能總是推斷出prod的類型。 在C ++ 11中,這可以使用auto 唉,也可以使用decltype ,但這也與auto一起添加到C ++ 11中。


許多C ++精英建議你應該盡可能使用auto Herb Sutter在最近的一次會議上說明了這一點的原因:

它更短。 它更方便。 它更具有前瞻性,因為如果你改變你的函數的返回類型, auto就可以了。

然而,他們也承認“鋒利的邊緣”。 在許多情況下, auto不能滿足您的需求。 當您需要進行類型轉換時,這些鋒利的邊緣可能會削減您


所以一方面我們有一個備受尊重的陣營告訴我們“在任何地方都可以使用auto ,但其他地方都沒有。” 然而,這對我來說並不合適。 auto提供的大多數好處都是在我稱之為“第一次寫入時間”的內容中提供的。 第一次寫一段代碼的時候。 當你正在編寫一大堆全新的代碼時,你可以繼續在任何地方使用auto ,並獲得你期望的行為。 當您編寫代碼時,您確切知道您的類型和變量發生了什么。 我不了解你,但是當我編寫代碼時,我的頭腦中不斷涌現着思緒。 我如何創建此循環? 我希望該功能返回什么樣的東西,所以我可以在這里使用它? 我如何寫這篇文章,以便在6個月后快速,正確且易於理解? 大部分內容從未在我編寫的代碼中直接表達,除了我編寫的代碼是這些思想的直接結果。

那時,使用auto會使編寫這段代碼更簡單,更容易。 簽名與未簽名,參考vs值,32位與64位等等的所有小分鍾,我不必擔心我的想法。我只是寫auto ,一切正常。

但這是我的auto問題。 6個月后,當重新訪問此代碼以添加一些主要的新功能時,我第一次編寫代碼時腦海中浮現的那種嗡嗡聲已經很久了。 很久以前,我的緩沖區已經被沖洗了,而且這些想法都沒有了。 如果我完成了我的工作,那么這些想法的本質就直接在我寫的代碼中表達出來。 通過查看函數和數據類型的結構,我可以對我的想法進行逆向工程。

如果auto隨處可見,那么很大一部分就會失去認知感。 我不知道我在想這個數據類型會發生什么,因為現在它被推斷了。 如果與運算符發生了微妙的關系,那么這種關系就不再由數據類型表示 - 它只是auto

維護變得更加困難,因為沒有必要重新創造大部分想法。 微妙的關系變得更加陰霾,一切都難以理解。

所以我不喜歡在任何地方使用auto 我認為這會使維護變得更加艱難。 這並不是說我相信auto應該只在需要的地方使用 相反,這是一種平衡行為。 我用來判斷我(或任何人的代碼)質量的四個標准是:效率,正確性,穩健性和可維護性。 沒有特別的順序。 如果我們設計一個auto使用的范圍,其中一方是“純粹可選的”而另一方是“嚴格要求的”,我覺得一般來說,越接近“純粹可選”,我們就越容易受到維護。

所有這一切,最后,我的哲學可以被稱為:

使用auto可以使代碼更好,但不管其他地方。 了解使用auto過度自由對可維護性的影響。

這里有兩個相互矛盾的興趣。 一方面,鍵入auto& Anywhere比簡單地計算每個循環的確切類型更簡單。 有些人會聲稱,它也更面向未來的 ,如果存放在未來的-我不同意特別的容器的類型改變,我寧願讓編譯器抱怨*,讓我弄清楚如果假設提出在循環中關於類型仍然持有。

另一方面,通過使用auto& (而不是更明確的int& ),您將隱藏讀者的類型。 閱讀代碼的維護者必須考慮在這個特定的上下文中auto意味着什么,而int顯然只有一個含義。 相同的人,或者至少是他們的一部分,會聲稱您不需要思考 ,如果您將鼠標懸停在變量上,IDE將告訴您類型...但我不使用IDE也不是特別喜歡老鼠......

總而言之,這主要是風格問題。 我更喜歡代碼中的類型,而不是編譯器為我推斷它們,因為我發現當我稍后回到代碼時更容易理解。 但是對於快速編碼,當我不想要在一周后維護這段代碼時, auto綽綽有余。

*這假設您使用標准兼容的編譯器,而VisualStudio不是其中的一個示例。 假設如果類型錯誤,非const引用將不會綁定到解除引用迭代器返回的值。 在VS中,編譯器很樂意轉換類型並將非const引用綁定到rvalue! 也許這就是為什么來自VS世界的Sutter建議在任何地方使用auto

這取決於你想用c做什么:

  • 你想使用副本嗎? 使用auto c
  • 您想使用原始項目並可能修改它們嗎? 使用auto& c
  • 您想使用原始項目而不是修改它們嗎? 使用const auto& c

我同意dasblinkenlight的回答 ,但既然你在詢問int&是否比auto&更好,我可以用這種方式解釋:

如果/當某人決定更改vector的類型時,請使用int& when您希望代碼中斷的時間。

例如:您的向量通常包含int16_t ,但是這個特定的向量需要更高的精度(假設int具有32位或更高的精度)。 您不希望有人將類型從int更改為int16_t並獲取包含計算中的靜默溢出的程序。

另一個例子:您的代碼如下所示:

namespace joes_lib
{
    int frobnicate(int);
}

for (int& c : vec) { c = frobnicate(c); }

在這里,如果有人將vec更改為vector<int16_t>或者更糟糕的是vector<unsigned> ,則auto將默默地成功並導致joe庫函數的精度損失。 編譯器可能會也可能不會生成有關此問題的警告。

這些示例看起來笨拙和模糊,因此您可能想要在循環中評論非auto類型的這種用法。

暫無
暫無

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

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