※ 引述《dreambegins ( ′-`)》之銘言:
for(int r=0; r<100; r++){
if(cache[index][r].v && cache[index][r].tag==tag){
cache[index][r].v=true;
cache[index][r].hit_count++;
enable_instructions[access]=2;
stillAccessing=false;
cout <<"(hit)";
break;
}
}
: 有點搞不清楚...虛心請教一下...
: 我想請問...以上的for()預設是執行100次
: 假設我在第55次的時候if()的條件成立了,然後第56~100次的for loop就不做了
: 那我的break放這裡對嗎?
: break是跳出if這個{}還是會跳出for的{} ?(我想要跳出整個for)
講一個跟 break 沒什麼關係的點.
這篇來談談這個例子有沒有寫成 for loop 的必要.
1. 迴圈計數器單調遞增/遞減
for(int r=0; r<100; r++)
看到程式碼如上, 可以很容易猜到你迴圈的邏輯可能只是:
"陣列某個區段內的元素都掃過一遍"
而索引又是從 0 開始跑, 更可能是在尋訪所有元素.
這時應該考慮改用 range-based for 而不是一般的 for loop.
你也可以 boost::irange 來搭配 range-based for 使用.
基本上會需要迴圈的時候, 通常是寫 while.
2. 迴圈裡的條件結構只有單個分支
像這樣有 if 沒有 else 的情況, 即是:
"只對某種條件成立的元素作操作"
有篩選的味道. 可以用 boost::adaptors::filtered 搭配
range-based for 只對你感興趣的元素跑迴圈.
3. 無條件 break
此迴圈的邏輯為:
"找到第一個符合條件的元素, 對其操作, 然後結束迴圈"
然後以下三行:
enable_instructions[access]=2;
stillAccessing=false;
cout <<"(hit)";
即為 "找到符合條件元素的話, 該作的標記動作", 嚴格算起來
可以寫在迴圈外面. 將上述區段拉出來之後, 迴圈本身就剩下沒
什麼內容了, 這時標準函式庫裡有更適合你的 std::find_if()
(或是 boost::find_if()) 可將程式碼改寫如下:
1. const auto& interested = boost::make_iterator_range(
2. cache[index], cache[index] + 100
3. );
4.
5. const auto& found = boost::find_if(
6. interested,
7. [&](const your_cache_type& cache) {
8. return cache.v && cache.tag == tag;
9. }
10. );
11.
12. if (found != boost::end(interested))
13. {
14. found->v = true;
15. ++found->hit_count;
16.
17. enable_instructions[access] = 2;
18. stillAccessing = false;
19. cout << "(hit)";
20. }
第 1-3 行決定要尋訪的陣列範圍, index 只有在這裡被用到,
因為它相對於接下來的邏輯只是常數, 所以沒必要再次出現.
第 5-10 行用函式呼叫來替我們作搜尋的動作, 尤其第 7-9 行
用 lambda expression 封裝了我們感興趣的條件, 而不是亂
糟糟的陣列索引取值運算.
第 12-20 行專注處理如果找到讓條件成立的物件時該做什麼事.
結論
我個人建議儘量使用 STL Algorithms 或是 Boost Range
Algorithms 來取代 for loops, 甚至連 range-based for
都可以被取代掉.
如此一來我們可以將邏輯附加在原本的元素上, 形成另一個
抽象化的容器, 然後更專注處理問題本身, 而不是最原始的
資料.
而上面改寫後第 1、5 行所產生的物件是可以在稍後被重複
使用的, 反而可以大大地減少重複程式碼的出現.