std::list 迭代器隨機移動:std::advance 才是正解list 內部為雙向鏈表,迭代器僅支援 ++/--,不支援 +/-/+=/-=。手寫迴圈移動雖可行,但 std::advance 是通用標準做法:
#include <list>
#include <iterator> // advance 定義於此
std::list<int> myList = {1,2,3,4,5};
auto it = myList.begin();
std::advance(it, 3); // 向前移動 3 位置,O(n)
advance 會根據迭代器類別自動選擇最佳策略:隨機存取迭代器(vector、deque)O(1) 跳躍;雙向/前向迭代器(list、map)O(n) 逐步移動。無需關心底層容器型別,程式碼更通用。
vector::resize() vs reserve():本質區別| 特性 | reserve(n) | resize(n) | resize(n, val) |
|---|---|---|---|
| 記憶體預留 | 是 | 是 | 是 |
| 建構元素 | 否 | 是(預設構造) | 是(複製 val) |
size() 變化 | 不變 | 變為 n | 變為 n |
| 後續新增方式 | push_back/insert | operator[] / 迭代器 | operator[] / 迭代器 |
std::vector<int> v;
v.reserve(100); // capacity=100, size=0
for (int i=0; i<100; ++i) v.push_back(i); // 逐個建構
v.resize(102); // size=102, 新增 2 個 value=0 的元素
v[100] = 1; // 直接存取有效
v[101] = 2;
口訣:reserve 只備容量,resize 真建元素。
vector 記憶體重新配置導致指標失效
struct Node { int id; Node* prev; };
std::vector<Node> vec;
for (int i=0; i<count; ++i) {
Node n; n.prev = &vec[some_index]; // 危險!
vec.push_back(n); // 可能觸發重新配置,prev 變懸空指標
}
vec.reserve(count); 避免重新配置size_t prev_idx; 索引不受重新配置影響原則:只要 vector 可能增長,絕不儲存元素內部指標/參考。
// MyLib.h
#ifdef MYLIB_EXPORTS
#define MYLIB_API __declspec(dllexport)
#else
#define MYLIB_API __declspec(dllimport)
#endif
extern "C" MYLIB_API int Add(int a, int b); // C 連結防止名稱修飾
// MyLib.cpp
#include "MyLib.h"
extern "C" MYLIB_API int Add(int a, int b) { return a + b; }
使用者專案:
MyLib.hMyLib.lib介面宣告差異:
// DllLib.h
#ifdef DLLLIB_EXPORTS
#define DLLLIB_API __declspec(dllexport)
#else
#define DLLLIB_API __declspec(dllimport)
#endif
extern "C" DLLLIB_API int Add(int a, int b);
建置產出 DllLib.dll、DllLib.lib(導入庫)、DllLib.h。
使用者專案:
DllLib.libDllLib.dllLoadLibrary + GetProcAddress,無需 .lib/.h| 特性 | 靜態庫 | 動態庫 |
|---|---|---|
| 程式碼複製 | 連結時複製進 EXE | 執行時共享單一副本 |
| 部署檔案 | 僅 EXE | EXE + DLL |
| 更新維護 | 需重新編譯 EXE | 替換 DLL 即可(介面相容) |
| 巢狀依賴 | 不能包含其他庫 | 可包含其他靜態/動態庫 |
| 除錯便利性 | 直接單步進入 | 需載入符號表,稍繁瑣 |
注意:DLL 內避免使用 cout 等螢幕輸出,否則主控台應用可能無輸出、GUI 應用可能死鎖。
std::advance 統一迭代器移動介面,勿手寫迴圈reserve/resize 語義截然不同,按需選擇__declspec 與 extern "C" 關鍵字