標籤:

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#會出現不同的效果?求解答。

TAG:編程 | STL | C | CC |