2016-05-31 70 views
-3

當我運行下面的代碼:爲什麼C++標準庫運算符接受rvalues?

std::string myString = "I'm a string."; 
const std::string::iterator &myIterator = ++myString.begin(); 
char c = *myIterator; 
std::cout << c << std::endl; 

我得到一個分段錯誤(O3帶編譯優化)。我認爲這是因爲++運營商返回std::string::iterator &而不是std::string::iterator,所以我們得到一個臨時的參考。有沒有原因爲什麼這不會導致編譯錯誤?也就是說,爲什麼不是簽名以下?

std::string::iterator &std::string::iterator::operator++() &; 

甚至更​​好,爲什麼不規範需要以下特徵,使我們能夠處理沒有問題,右值?

std::string::iterator &std::string::iterator::operator++() &; 
std::string::iterator std::string::iterator::operator++() &&; 
+4

[無法重現](https://ideone.com/I9Z8De)。你確定這是因爲這些線?在附註中,即使'++'返回引用,'myIterator'也不是引用,因此它將複製值 – Rakete1111

+3

這工作正常。你能發佈完整的代碼嗎? – Sumeet

+0

是的,你是對的。我修改了這個例子,它現在應該會崩潰。 –

回答

0

你已經發布的代碼看起來合法的對我說:std::string::iterator myIterator = ++myString.begin();副本迭代器引用到myIterator所以有到無的臨時懸掛引用。

我的心理調試的力量告訴我,你的實際代碼有兩個問題一個:

  • 你的字符串是即使你認爲它有它文本實際上是空的。在這種情況下,++begin()無效。
  • 您在之後改變了字符串,您以迭代器複製的方式使迭代器失效。
+0

我的心理預測是代碼示例應該是'std :: string :: iterator&myIterator = ++ myString.begin();'在這種情況下實際上存在懸掛參考。 –

+0

良好的調用(儘管我最初也有一個'const')。不過,我仍然不確定爲什麼應該成功編譯。 –

0

@ M.M的評論很有見地。特別是,我的第二個建議會限制庫在實現迭代器中的選項,因爲迭代器不需要作爲右值來增量(參考:http://en.cppreference.com/w/cpp/iterator/next),事實上,std :: string :: iterator可以實現爲char *,這是不可遞增的作爲右值。

選擇是否遵循我的第一個建議似乎是一個庫實現的決定,因爲標準要求迭代器可以做什麼,而不是它們不能做什麼,以免不必要地限制哪些類型可以用作迭代器。當然,在這一點上,更改實現可能會導致用戶代碼的重大更改。