C++ primer 第四版這段關於vector的程序是否有未定義的行為?
本人在閱讀C++ primer第四版(2013 年7月北京第29次印刷)第九章順序容器一節時,在第276頁發現了如下一行程序
first = v.insert(++first,42);按照C++標準,一個語句中出現兩個賦值語句,是否是一種未定義行為?本人查閱了網上的資料,得知之前的印刷版本這個語句為first = v.insert(first,42);但是這個語句不能實現書中敘述的功能。在本人購買的印刷版本中,應該是對程序做了校準。這個校準正確嗎?
這個不是未定義行為。
因為函數調用按規定是一個序列點;因此執行完v.insert()時,++first一定是已經完成了賦值的;當v.insert()執行之後,再修改first,就成了另外一對序列點之間發生的事情了。所以整個過程沒有二義性。
但如果寫成:
v.insert(++first, *(++first))
那麼這就是未定義的。
因為函數調用是一個序列點,但參數求值不是;那麼這裡的兩個++first就無法確定實際發生的次序。
這裡有篇文章寫的很詳細:
http://caole.net/diary/sequence_pointer.html#sec-3
不過,還是盡量不要在程序寫這種「微妙」的代碼。因為稍有不慎就可能弄出問題。
甚至,即便你寫的時候查了很多資料,小心翼翼保證沒問題,將來維護時,說不定在哪裡改了一點點,未定義問題就又出來了。
————————————————————————
隨便提一下,原書中的第一個例子,是為了展示另外一種未定義行為,和前面的討論無關。
這個未定義行為是:
由於容器以及相關迭代器的內部實現各不相同;在某些容器在插入值後,由於實現所限,可能導致原有的迭代器失效。
所以:
1、插入值後,容器的end迭代器可能已經失效。所以不能保留它,而應該用v.end()重新計算。
2、first迭代器在執行完插入操作後,同樣可能已經失效。所以需要用v.insert()的返回值重新給它賦值;如果繼續使用,同樣是未定義行為。
2的一個推論是:first++是永遠不應該在insert的參數中出現的,因為它毫無作用。
看著代碼好奇怪,總後發現原來書中的例子是為了展示一個錯誤.正常的C++代碼, 不用循環.
1.插入n個值
v.insert(pos_iter, n, 42);2.插入from, to一組值v.insert(pos_iter, from, to);這個地方作者想說的是雖然有些vector::end()實現會返回一個常量值(iterator超過vector的長度後被賦一個常量值,表示到達了vector結尾),但是大多數的vector::end()實現不是這樣,那種實現返回了vector有效數據的結尾地址+1,當vector發生reallocation行為的時候,這個代碼就行不通了,因為last變數已經失效了。
推薦閱讀:
※c/c++中簡單加法出現奇怪的錯誤?
※如何使用C++11實現跨平台的定時器timer?
※在 Windows 上不用 Win32 API 可以繪製出一個窗口么?
※我用的是visual studio 2010 c語言為什麼學了好長時間還是控制台程序和dos窗口啊?
※為什麼使用virtual關鍵字在C++與C#會出現不同的效果?求解答。