恩恩 這本書是金牌QA和RD的必備武器,每天學幾章,天天樂呵呵~~
int main() { vector<Date> e; copy( istream_iterator<Date>( cin ), istream_iterator<Date>(), back_inserter( e ) ); vector<Date>::iterator first = find( e.begin(), e.end(), "01/01/95" ); vector<Date>::iterator last = find( e.begin(), e.end(), "12/31/95" ); *last = "12/30/95"; copy( first, last, ostream_iterator<Date>( cout, "\n" ) ); e.insert( --e.end(), TodaysDate() ); copy( first, last, ostream_iterator<Date>( cout, "\n" ) );}
至少四個迭代器錯誤,求bug free;
不是哥眼拙,一眼看下來真的一個都沒有看出來。。。擦,哥還不信咱一個RD幹不了QA的活!拷貝代碼,gcc一下,擦,居然編譯過了。。。
好吧,哥真的要GG?NO。。。
不就是測試麼,邊界,特殊用例,邏輯覆蓋。。。以前一個很好的QAMM還是讓我學了一些東西,從邊界開始看!
find完了沒有判斷是否真的找到,好吧,解引用錯了吧?copy使用未定義的錯了吧?直接貢獻了三個bug。。。
坑爹呢
還有一個實在找不到,看看答案:
The reason is simple, if a little obscure: On popular implementations of the standard library,vector<Date>::iterator is often simply a
Date*, and the C++ language doesn't allow you to modify temporaries of builtin type. For example, the following plain-jane code is also illegal:
Date* f(); // function that returns a Date* p = --f(); // error, but could be "f() - 1"
結論不是很有說服力,但是說實話,我也不是能寫出--vec.end()的瘋子。。。
總結的原文如下:
To summarize: When using iterators, be aware of four main issues.
Valid values: Is the iterator dereferenceable? For example, writing "*e.end()" is always a programming error.
Valid lifetimes: Is the iterator still valid when it's being used? Or has it been invalidated by some operation since we obtained it?
Valid ranges: Is a pair of iterators a valid range? Is first really before (or equal to)last? Do both really point into the same container?
Illegal builtin manipulation: For example, is the code trying to modify a temporary of builtin type, as in "--e.end()" above? (Fortunately, the compiler can often catch this kind of mistake for you, and for iterators of class type,
the library author will often choose to allow this sort of thing for syntactic convenience.)
總的來說呢,用迭代器的時候記著哥傳授給你的四句天一真訣就妥妥的啦:
- 在寫下*的時候,想想這個長得像鑽石的該死的東西可能會真的像鑽石一樣cost(core)你很多;
- 迭代器是個不忠貞的傢伙,幾乎會在所有的容器(list是個例外)執行插入刪除時失效(迭代器的失效的原因是自增長,重新申請了記憶體
)
- 當需要一個迭代器範圍的時候,你最好確定一下,前面的真的比後面的小?真的嗎?真的嗎?真的嗎?
- 不要嘗試修改一個對你來說不存在的臨時變數
iterm2
這個木有題目可以做了,不過,嗯嗯,書上的解決方案相當的完美,直接代碼吧:
struct ci_char_traits : public char_traits<char> // just inherit all the other functions // that we don't need to replace{ static bool eq( char c1, char c2 ) { return toupper(c1) == toupper(c2); } static bool lt( char c1, char c2 ) { return toupper(c1) < toupper(c2); } static int compare( const char* s1, const char* s2, size_t n ) { return memicmp( s1, s2, n ); } // if available on your platform, // otherwise you can roll your own static const char* find( const char* s, int n, char a ) { while( n-- > 0 && toupper(*s) != toupper(a) ) { ++s; } return n >= 0 ? s : 0; }};And finally, the key that brings it all together:typedef basic_string<char, ci_char_traits> ci_string;
直接使用traits搞定,精彩~
後一節有一個“使用繼承的方式安全嗎?“的問題,that's a good question!
(1) the proper uses (and improper abuses) of inheritance;知道為啥用,也知道為啥不用繼承;
(2) the implications of the fact that there are only static members;使用靜態函數(符合is-a或者work-like-a的模型),
(3) the fact that char_traits objects are never used polymorphically.從不使用多態保證了其安全性
註:迭代器失效的原因(摘自http://blog.csdn.net/zhongjiekangping/article/details/5624922):
vector迭代器的幾種失效的情況: 1.當插入(push_back)一個元素後,end操作返回的迭代器肯定失效。 2.當插入(push_back)一個元素後,capacity傳回值與沒有插入元素之前相比有改變,則需要重新載入整個容器,此時first和end操作返回的迭代器都會失效。 3.當進行刪除操作(erase,pop_back)後,指向刪除點的迭代器全部失效;指向刪除點後面的元素的迭代器也將全部失效。
deque迭代器的失效情況: 在C++Primer一書中是這樣限定的: 1.在deque容器首部或者尾部插入元素不會使得任何迭代器失效。 2.在其首部或尾部刪除元素則只會使指向被刪除元素的迭代器失效。 3.在deque容器的任何其他位置的插入和刪除操作將使指向該容器元素的所有迭代器失效。但是:我在vs2005測試發現第一條都不滿足,不知為何?等以後深入STL以後慢慢的領會吧!
只有list的迭代器好像很少情況下會失效。也許就只是在刪除的時候,指向被刪除節點的迭代器會失效吧,其他的還沒有發現。