在C++11标准引入的众多特性中,Lambda表达式无疑是最具革命性的特性之一。作为一名长期奋战在Windows平台开发的C++程序员,我深刻体会到Lambda如何改变了我们的编码方式。它不仅仅是一种语法糖,更是一种思维方式的转变——让我们能够以更自然、更直观的方式表达函数式编程思想。
想象一下这样的场景:你正在处理一个用户列表,需要筛选出所有VIP用户并按积分降序排列。在Lambda出现之前,我们不得不单独定义比较函数或函数对象,代码分散且难以维护。而现在,我们可以直接在调用std::sort和std::copy_if的地方内联定义这些逻辑,代码可读性大幅提升。
Lambda表达式本质上是一个匿名函数对象(仿函数),但比传统仿函数更轻量、更灵活。编译器会为每个Lambda生成一个唯一的类型,这个类型重载了函数调用运算符operator()。与普通函数相比,Lambda最大的优势在于它可以捕获上下文变量,形成闭包(closure)。
提示:在Windows平台开发中,Lambda特别适合用于消息处理、回调函数和异步操作等场景,能显著减少样板代码量。
让我们拆解Lambda表达式的完整语法结构:
cpp复制[capture-list] (parameters) mutable -> return-type {
// 函数体
}
捕获列表(capture-list):决定了Lambda如何访问外部变量,这是与普通函数最本质的区别。捕获方式包括:
[]:不捕获任何变量[=]:以值方式捕获所有变量(默认const)[&]:以引用方式捕获所有变量[var]:仅捕获特定变量[this]:捕获当前类实例参数列表:与普通函数参数类似,但C++14后支持auto参数
mutable:允许修改值捕获的变量(不影响外部变量)
返回类型:可省略(编译器自动推导),复杂逻辑需显式声明
理解捕获机制是掌握Lambda的关键。让我们通过一个Windows GUI编程的典型场景来说明:
cpp复制// 假设在对话框类中
void CMyDialog::OnButtonClick()
{
int retryCount = 0; // 重试计数器
CString statusMsg; // 状态信息
// 异步操作的回调Lambda
auto callback = [=, &statusMsg](DWORD result) mutable {
if(result == ERROR_SUCCESS) {
statusMsg = L"操作成功";
} else {
retryCount++; // mutable允许修改值捕获的副本
statusMsg.Format(L"第%d次重试中...", retryCount);
if(retryCount < 3) {
RetryOperation(callback); // 再次尝试
}
}
UpdateUI(statusMsg); // 更新界面
};
StartAsyncOperation(callback); // 开始异步操作
}
在这个例子中:
retryCount以值方式捕获,使用mutable允许修改内部副本statusMsg以引用方式捕获,可直接修改原变量注意:引用捕获的变量必须确保在Lambda执行时仍然有效,否则会导致未定义行为。这在异步编程中尤为重要。
在类成员函数中使用Lambda时,经常需要捕获this指针来访问成员变量。但这里有几个关键注意事项:
cpp复制class CMyClass {
public:
void StartAsyncTask() {
// 危险!如果对象销毁时任务仍在运行...
auto task = [this]() {
this->ProcessData(); // 访问成员函数
m_status = 100; // 修改成员变量
};
std::thread(task).detach(); // 分离线程
}
private:
int m_status;
};
更安全的做法是使用shared_from_this(对于继承自enable_shared_from_this的类):
cpp复制auto task = [self = shared_from_this()]() {
self->ProcessData();
};
或者在C++14后使用广义捕获:
cpp复制auto task = [self = weak_ptr<CMyClass>(shared_from_this())]() {
if(auto ptr = self.lock()) {
ptr->ProcessData();
}
};
Lambda与STL算法是天作之合。让我们看几个Windows开发中的实用示例:
cpp复制// 对窗口列表按Z序排序
std::vector<HWND> windows = GetWindowList();
std::sort(windows.begin(), windows.end(), [](HWND a, HWND b) {
return GetWindowZOrder(a) < GetWindowZOrder(b);
});
// 查找第一个可见窗口
auto it = std::find_if(windows.begin(), windows.end(), [](HWND hwnd) {
return IsWindowVisible(hwnd) && !IsIconic(hwnd);
});
// 转换窗口句柄为标题
std::vector<CString> titles;
std::transform(windows.begin(), windows.end(),
std::back_inserter(titles),
[](HWND hwnd) {
CString title;
GetWindowText(hwnd, title.GetBuffer(256), 256);
title.ReleaseBuffer();
return title;
});
在Windows系统编程中,我们经常需要处理资源管理。Lambda可以优雅地实现RAII模式:
cpp复制auto guard = [hFile = INVALID_HANDLE_VALUE](HANDLE handle) mutable {
hFile = handle;
return [hFile] {
if(hFile != INVALID_HANDLE_VALUE) {
CloseHandle(hFile);
}
};
}(CreateFile(...));
// 当guard离开作用域时,文件句柄自动关闭
C++14引入了通用Lambda,允许参数使用auto:
cpp复制// 可用于任何可调用对象的包装器
auto logger = [](auto&& func, auto&&... args) {
std::wcout << L"调用开始" << std::endl;
auto result = std::forward<decltype(func)>(func)(
std::forward<decltype(args)>(args)...);
std::wcout << L"调用结束" << std::endl;
return result;
};
// 既可以用于普通函数
logger(MessageBox, NULL, L"Hello", L"Title", MB_OK);
// 也可以用于成员函数
logger([this] { return this->DoWork(); });
虽然Lambda通常会被编译器内联,但在某些情况下需要注意:
优化建议:
const auto变量cpp复制// 不好的做法:在循环中重复创建相同Lambda
for(int i = 0; i < 1000000; ++i) {
std::find_if(begin, end, [](auto x) { return x > 0; });
}
// 好的做法:提前创建Lambda
const auto pred = [](auto x) { return x > 0; };
for(int i = 0; i < 1000000; ++i) {
std::find_if(begin, end, pred);
}
在Windows GUI编程中,Lambda可以大幅简化消息处理:
cpp复制// 传统WndProc
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch(msg) {
case WM_COMMAND: /* 处理 */ break;
// 其他消息...
}
}
// 使用Lambda的现代风格
window.OnMessage(WM_COMMAND, [](WPARAM wParam, LPARAM lParam) {
auto id = LOWORD(wParam);
if(id == IDC_BUTTON1) {
// 处理按钮点击
return true; // 已处理
}
return false; // 未处理
});
Windows线程池API与Lambda配合得天衣无缝:
cpp复制// 提交工作项到线程池
PTP_WORK work = CreateThreadpoolWork([](PTP_CALLBACK_INSTANCE, void* context) {
auto data = static_cast<MyData*>(context);
// 处理数据...
delete data; // 清理
}, new MyData{}, nullptr);
SubmitThreadpoolWork(work);
// 更安全的C++封装
template<typename F>
void RunInThreadPool(F&& f) {
auto task = new std::decay_t<F>(std::forward<F>(f));
CreateThreadpoolWork([](PTP_CALLBACK_INSTANCE, void* p) {
auto task = static_cast<F*>(p);
(*task)();
delete task;
}, task, nullptr);
}
// 使用
RunInThreadPool([this] {
this->BackgroundTask();
});
Lambda捕获引用时最常见的错误是悬挂引用:
cpp复制std::function<void()> CreateTask() {
int local = 42;
return [&local] {
std::cout << local; // 危险!local可能已销毁
};
}
// 正确做法:值捕获需要长期使用的变量
std::function<void()> CreateTask() {
int local = 42;
return [local] { // 值捕获
std::cout << local;
};
}
在Windows COM编程中要特别注意:
cpp复制HRESULT SafeCOMCall() {
CComPtr<IDispatch> ptr;
HRESULT hr = CoCreateInstance(..., &ptr);
if(FAILED(hr)) return hr;
// 危险:Lambda可能抛出异常
auto action = [ptr] {
VARIANT result;
ptr->Invoke(..., &result); // 可能抛出
VariantClear(&result);
};
try {
action();
} catch(...) {
return E_FAIL;
}
return S_OK;
}
<lambda_...>类型decltype获取Lambda的实际类型std::function方便调试#pragma显示Lambda的展开代码:cpp复制#pragma optimize("", off)
auto debugLambda = [] { /* 代码 */ };
#pragma optimize("", on)
虽然Windows平台对C++20的支持还在逐步完善,但了解这些新特性很有必要:
cpp复制auto make_visitor = []<typename... Ts>(std::variant<Ts...> var) {
std::visit([]<typename T>(const T& value) {
if constexpr(std::is_same_v<T, std::string>) {
std::cout << "String: " << value;
} else {
std::cout << "Other: " << value;
}
}, var);
};
cpp复制auto [x, y] = GetPoint();
auto lambda = [x = x, y = y] { /* 使用x,y */ };
cpp复制constexpr auto square = [](int x) { return x * x; };
static_assert(square(5) == 25);
在实际项目中采用这些新特性时,需要检查编译器和Windows SDK的支持情况。Visual Studio 2019 16.8及以上版本对大多数C++20 Lambda特性提供了良好支持。
在开发UWP应用或Windows Runtime组件时,Lambda与COM的交互有一些特殊注意事项:
cpp复制// 创建异步操作
IAsyncOperation<int>^ Class::DoWorkAsync()
{
return concurrency::create_async([](concurrency::progress_reporter<float> reporter) {
for(int i = 0; i < 100; ++i) {
reporter.report(i / 100.0f); // 报告进度
std::this_thread::sleep_for(100ms);
}
return 42; // 最终结果
});
}
// 使用co_await调用
IAsyncAction Class::ConsumeAsync()
{
auto result = co_await DoWorkAsync();
// 处理结果...
}
关键点:
ComPtr)在游戏开发、实时处理等性能敏感场景中,Lambda的使用需要特别小心:
cpp复制// 不好的做法:捕获不需要的变量
auto lambda = [=] { return globalConfig.value; };
// 好的做法:明确捕获列表
auto lambda = [] { return globalConfig.value; };
cpp复制auto fastPath = []() noexcept {
// 保证不抛异常的实现
};
使用编译器内联提示:
cpp复制auto criticalLambda = []() __forceinline {
// 性能关键代码
};
在Visual Studio中可以通过汇编输出验证Lambda是否被内联。
Lambda使得许多设计模式的实现变得更加简洁:
cpp复制class Sorter {
public:
using CompareFunc = std::function<bool(int, int)>;
void SetStrategy(CompareFunc f) { m_compare = f; }
void Sort(std::vector<int>& items) {
std::sort(items.begin(), items.end(), m_compare);
}
private:
CompareFunc m_compare;
};
// 使用
Sorter sorter;
sorter.SetStrategy([](int a, int b) { return a > b; }); // 降序
sorter.SetStrategy([](int a, int b) { return abs(a) < abs(b); }); // 按绝对值升序
cpp复制class EventSource {
public:
using Handler = std::function<void(int)>;
void AddHandler(Handler h) { m_handlers.push_back(h); }
void FireEvent(int value) {
for(auto& h : m_handlers) h(value);
}
private:
std::vector<Handler> m_handlers;
};
// 使用
EventSource source;
source.AddHandler([](int v) { std::cout << "Event: " << v; });
source.AddHandler([this](int v) { this->OnEvent(v); });
C++17引入的并行算法与Lambda配合使用可以充分发挥多核性能:
cpp复制#include <execution>
void ProcessLargeData(std::vector<Data>& dataset)
{
// 并行转换
std::transform(std::execution::par,
dataset.begin(), dataset.end(),
dataset.begin(),
[](const Data& d) {
return ProcessItem(d); // 处理每个元素
});
// 并行过滤
std::vector<Data> results;
std::copy_if(std::execution::par,
dataset.begin(), dataset.end(),
std::back_inserter(results),
[](const Data& d) {
return d.IsValid(); // 过滤条件
});
}
在Windows平台上,这些并行算法通常使用线程池实现,与PPL(Parallel Patterns Library)有很好的协同。
在Windows开发中,经常需要与C#、JavaScript等语言交互,Lambda的跨语言传递有一些特殊技巧:
cpp复制// C++/CLI代码
void ManagedClass::RegisterCallback(Action<int>^ callback)
{
// 将托管委托转换为原生函数指针
auto nativeCallback = static_cast<void(*)(int)>(
Marshal::GetFunctionPointerForDelegate(callback).ToPointer());
// 使用Lambda包装
m_nativeObject->SetHandler([nativeCallback](int value) {
nativeCallback(value);
});
}
cpp复制// 在UWP应用中
void WebViewInterop()
{
auto webView = ref new WebView();
// 注册JavaScript回调
webView->ScriptNotify += ref new NotifyEventHandler(
[this](Object^ sender, NotifyEventArgs^ e) {
auto value = e->Value;
// 处理来自JavaScript的通知
});
// 调用JavaScript函数
webView->InvokeScriptAsync(
"eval",
ref new Vector<String^>{ "window.onclick = function() { window.external.notify('click'); }" });
}
测试包含Lambda的代码需要特殊考虑:
cpp复制TEST_METHOD(TestLambdaBehavior)
{
auto lambda = [](int x) { return x * 2; };
Assert::AreEqual(4, lambda(2));
Assert::AreEqual(0, lambda(0));
Assert::AreEqual(-6, lambda(-3));
}
cpp复制TEST_METHOD(TestSortWithCustomLambda)
{
std::vector<int> data = {3,1,4,2};
std::sort(data.begin(), data.end(), [](int a, int b) {
return a > b; // 降序
});
const std::vector<int> expected = {4,3,2,1};
Assert::IsTrue(data == expected);
}
cpp复制TEST_METHOD(TestLambdaCapture)
{
int counter = 0;
auto lambda = [&counter]() { counter++; };
lambda();
Assert::AreEqual(1, counter);
lambda();
Assert::AreEqual(2, counter);
}
Lambda在编译期计算中也有妙用:
cpp复制constexpr auto hash = [](const char* str) {
size_t value = 0;
for(; *str; ++str) value = value * 31 + *str;
return value;
};
static_assert(hash("hello") == 99162322, "Hash mismatch");
cpp复制template<typename... Ts>
auto make_tuple_from_variadic(Ts... args)
{
return [args...] { return std::tuple<Ts...>(args...); }();
}
C++20协程与Lambda的结合创造了新的可能性:
cpp复制task<int> AsyncTask()
{
auto fetch = []() -> task<std::string> {
co_await resume_background();
co_return DownloadString("https://example.com");
};
auto process = [](std::string s) -> task<int> {
co_await resume_background();
co_return s.length();
};
auto data = co_await fetch();
auto result = co_await process(data);
co_return result;
}
在Windows平台上,这种模式特别适合I/O密集型操作。
虽然Lambda功能强大,但有时其他选择可能更合适:
cpp复制// 适用于C接口回调
void RegisterCallback(void (*callback)(int))
{
callback(42);
}
// 使用Lambda(需无捕获)
RegisterCallback([](int x) { std::cout << x; });
cpp复制// 类型擦除,允许捕获
std::function<void(int)> callback;
callback = [this](int x) { this->Handle(x); };
cpp复制// 需要重用或复杂状态时
struct Comparer {
bool reverse;
bool operator()(int a, int b) const {
return reverse ? a > b : a < b;
}
};
std::sort(v.begin(), v.end(), Comparer{true});
利用Lambda可以创建更安全的API包装器:
cpp复制template<typename F>
void EnumWindowsWrapper(F handler)
{
struct Context {
F& func;
static BOOL CALLBACK EnumProc(HWND hwnd, LPARAM lParam) {
auto& ctx = *reinterpret_cast<Context*>(lParam);
return ctx.func(hwnd) ? TRUE : FALSE;
}
} ctx{handler};
EnumWindows(&Context::EnumProc, reinterpret_cast<LPARAM>(&ctx));
}
// 使用
EnumWindowsWrapper([](HWND hwnd) {
wchar_t title[256];
GetWindowText(hwnd, title, 256);
std::wcout << title << std::endl;
return true; // 继续枚举
});
在实现COM接口时,Lambda可以简化QueryInterface等方法的实现:
cpp复制class ComObject : public IUnknown {
public:
HRESULT QueryInterface(REFIID riid, void** ppv) override
{
static const QITAB qit[] = {
QITABENT(ComObject, IUnknown),
{ nullptr }
};
return QISearch(this, qit, riid, ppv);
}
ULONG AddRef() override { return ++m_ref; }
ULONG Release() override { if(--m_ref == 0) delete this; return m_ref; }
// 使用Lambda实现事件通知
void SetEventHandler(std::function<void(int)> handler)
{
m_handler = handler;
}
void FireEvent()
{
if(m_handler) m_handler(42);
}
private:
std::function<void(int)> m_handler;
ULONG m_ref = 1;
};
Windows注册表操作可以通过Lambda变得更安全:
cpp复制void ReadRegistryWithFallback()
{
auto readValue = [](HKEY key, LPCWSTR path, LPCWSTR value) -> std::optional<DWORD> {
DWORD data = 0, size = sizeof(data);
if(ERROR_SUCCESS == RegGetValue(key, path, value, RRF_RT_REG_DWORD,
nullptr, &data, &size)) {
return data;
}
return std::nullopt;
};
auto value = readValue(HKEY_CURRENT_USER,
L"Software\\MyApp",
L"Settings");
if(!value) {
value = readValue(HKEY_LOCAL_MACHINE,
L"Software\\MyApp",
L"DefaultSettings");
}
// 使用value...
}
在实现安全相关功能时,Lambda需要特别注意:
cpp复制void RunWithPrivilege(const std::function<void()>& action)
{
HANDLE token;
if(OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &token)) {
TOKEN_PRIVILEGES privs = {0};
privs.PrivilegeCount = 1;
privs.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
LookupPrivilegeValue(nullptr, SE_DEBUG_NAME, &privs.Privileges[0].Luid);
AdjustTokenPrivileges(token, FALSE, &privs, 0, nullptr, nullptr);
CloseHandle(token);
}
__try {
action(); // 执行特权操作
} __except(EXCEPTION_EXECUTE_HANDLER) {
// 处理异常
}
// 恢复原始权限...
}
Windows服务开发中,Lambda可以简化控制处理:
cpp复制void WINAPI ServiceMain(DWORD argc, LPWSTR* argv)
{
auto serviceStatus = SERVICE_STATUS{
.dwServiceType = SERVICE_WIN32_OWN_PROCESS,
.dwCurrentState = SERVICE_RUNNING,
.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN
};
auto handler = [&serviceStatus](DWORD ctrl) -> DWORD {
switch(ctrl) {
case SERVICE_CONTROL_STOP:
serviceStatus.dwCurrentState = SERVICE_STOP_PENDING;
SetServiceStatus(..., &serviceStatus);
// 清理工作...
return NO_ERROR;
// 其他控制码处理...
}
};
RegisterServiceCtrlHandlerEx(L"MyService",
[](DWORD ctrl, DWORD eventType, void* eventData, void* context) -> DWORD {
return (*static_cast<decltype(handler)*>(context))(ctrl);
}, &handler);
// 服务主循环...
}
在自定义消息循环中,Lambda可以简化消息过滤:
cpp复制void RunMessageLoop(std::function<bool(MSG&)> filter)
{
MSG msg;
while(GetMessage(&msg, nullptr, 0, 0)) {
if(!filter || filter(msg)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
// 使用
RunMessageLoop([](MSG& msg) {
// 过滤掉某些消息
return msg.message != WM_MOUSEMOVE;
});
在编写Windows DLL时,Lambda的跨模块使用需要特别注意:
cpp复制// 错误做法:导出包含Lambda的函数
__declspec(dllexport) void BadExport()
{
auto lambda = [] { /* ... */ };
lambda();
}
// 正确做法:将Lambda转换为函数指针
using Callback = void(*)();
__declspec(dllexport) void GoodExport(Callback cb)
{
cb();
}
// 调用方
GoodExport([] { /* 无捕获Lambda */ });
调试Lambda代码时的一些实用技巧:
设置符号名称:通过赋值给命名变量方便调试
cpp复制auto debugNamedLambda = [](int x) { return x * 2; };
断点条件:在Lambda内设置条件断点
cpp复制std::for_each(v.begin(), v.end(), [](int x) {
if(x == 42) { // 在此处设置条件断点
DebugBreak();
}
});
输出调试信息:
cpp复制auto lambda = [](auto x) {
OutputDebugString(std::to_wstring(x).c_str());
return x;
};
使用Lambda简化性能监控代码:
cpp复制auto Measure(const std::function<void()>& action)
{
LARGE_INTEGER start, end, freq;
QueryPerformanceFrequency(&freq);
QueryPerformanceCounter(&start);
action();
QueryPerformanceCounter(&end);
return (end.QuadPart - start.QuadPart) * 1000.0 / freq.QuadPart;
}
// 使用
auto time = Measure([] {
// 要测量的代码
});
std::cout << "耗时: " << time << "ms\n";
处理回调时,Lambda的生命周期管理至关重要:
cpp复制class EventSystem {
public:
template<typename F>
int RegisterHandler(F&& handler)
{
int id = m_nextId++;
m_handlers.emplace(id, std::forward<F>(handler));
return id;
}
void UnregisterHandler(int id)
{
m_handlers.erase(id);
}
void FireEvent(int value)
{
for(auto& [id, handler] : m_handlers) {
handler(value);
}
}
private:
std::map<int, std::function<void(int)>> m_handlers;
int m_nextId = 1;
};
// 使用
EventSystem events;
auto id = events.RegisterHandler([this](int v) { this->OnEvent(v); });
// ...
events.UnregisterHandler(id);
封装剪贴板操作为Lambda形式更安全:
cpp复制void WithClipboard(std::function<void()> action)
{
if(OpenClipboard(nullptr)) {
action();
CloseClipboard();
}
}
// 使用
WithClipboard([] {
if(auto handle = GetClipboardData(CF_TEXT)) {
if(auto text = static_cast<char*>(GlobalLock(handle))) {
std::cout << "剪贴板内容: " << text;
GlobalUnlock(handle);
}
}
});
文件I/O操作可以通过Lambda变得更安全:
cpp复制template<typename F>
void WithFile(LPCWSTR path, DWORD access, F&& action)
{
auto handle = CreateFile(path, access, FILE_SHARE_READ,
nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
if(handle != INVALID_HANDLE_VALUE) {
auto guard = wil::scope_exit([handle] { CloseHandle(handle); });
action(handle);
}
}
// 使用
WithFile(L"test.txt", GENERIC_READ, [](HANDLE hFile) {
char buffer[1024];
DWORD read;
if(ReadFile(hFile, buffer, sizeof(buffer), &read, nullptr)) {
std::cout << std::string_view(buffer, read);
}
});
在GDI绘图中使用Lambda可以简化资源管理:
cpp复制void DrawWithDC(HWND hwnd, std::function<void(HDC)> drawer)
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
auto guard = wil::scope_exit([hwnd, &ps] { EndPaint(hwnd, &ps); });
drawer(hdc);
}
// 使用
DrawWithDC(hwnd, [](HDC hdc) {
auto pen = CreatePen(PS_SOLID, 1, RGB(255,0,0));
auto oldPen = SelectObject(hdc, pen);
auto guard = wil::scope_exit([hdc, oldPen] { SelectObject(hdc, oldPen); });
MoveToEx(hdc, 0, 0, nullptr);
LineTo(hdc, 100, 100);
});
在Windows内核驱动开发中,Lambda的使用受到严格限制:
替代方案是使用简单的函数指针:
cpp复制DRIVER_INITIALIZE DriverEntry;
NTSTATUS DriverEntry(PDRIVER_OBJECT driver, PUNICODE_STRING reg)
{
driver->DriverUnload = [](PDRIVER_OBJECT drv) {
// 不允许!内核模式不支持Lambda捕获
};
// 正确做法
driver->DriverUnload = DriverUnload;
return STATUS_SUCCESS;
}
VOID DriverUnload(PDRIVER_OBJECT driver)
{
// 清理代码
}
在重叠I/O操作中使用Lambda处理完成通知:
cpp复制void ReadFileAsync(HANDLE hFile, std::function<void(DWORD, const char*, DWORD)> callback)
{
auto buffer = std::make_unique<char[]>(1024);
auto overlapped = std::make_unique<OVERLAPPED>();
auto wrapper = new std::function<void(DWORD)>(
[buffer = std::move(buffer), overlapped = std::move(overlapped), callback](DWORD error) mutable {
callback(error, buffer.get(), overlapped->InternalHigh);
delete this;
});
ReadFileEx(hFile, buffer.get(), 1024, overlapped.get(),
[](DWORD error, DWORD bytes, LPOVERLAPPED overlapped) {
auto wrapper = reinterpret_cast<std::function<void(DWORD)>*>(
overlapped->hEvent);
(*wrapper)(error);
});
overlapped->hEvent = wrapper;
}
将SEH与Lambda结合需要特别注意:
cpp复制template<typename F>
auto SafeSEH(F&& func) -> decltype(func())
{
__try {
return func();
} __except(EXCEPTION_EXECUTE_HANDLER) {
return decltype(func()){};
}
}
// 使用
auto result = SafeSEH([] {
volatile int* p = nullptr;
return *p; // 访问违例
});
在自定义内存管理中应用Lambda:
cpp复制template<typename F>
void WithMemory(F&& action)
{
auto mem = VirtualAlloc(nullptr, 4096, MEM_COMMIT, PAGE_READWRITE);
if(mem) {
auto guard = wil::scope_exit([mem] { VirtualFree(mem, 0, MEM_RELEASE); });
action(mem);
}
}
// 使用
WithMemory([](void* mem) {
ZeroMemory(mem, 4096);
// 使用内存...
});
封装进程操作为Lambda形式:
cpp复制template<typename F>
void WithProcess(DWORD pid, DWORD access, F&& action)
{
auto handle = OpenProcess(access, FALSE, pid);
if(handle) {
auto guard = wil::scope_exit([handle] { CloseHandle(handle); });
action(handle);
}
}
// 使用
WithProcess(1234, PROCESS_QUERY_INFORMATION, [](HANDLE hProcess) {
DWORD exitCode;
if(GetExitCodeProcess(hProcess, &exitCode)) {
std::cout << "Exit code: " << exitCode;
}
});
结合TLS使用Lambda:
cpp复制void ThreadSpecificOperation(std::function<void()> action)
{
static DWORD tlsIndex = TlsAlloc();
auto guard = wil::scope_exit([] { TlsFree(tlsIndex); });
if(!TlsGetValue