C++17から導入される範囲 for ループの制限緩和で何が変わるか
概要
C++17で範囲forループのbeginとendで違う型を指定できるようになりました。
範囲 for ループの制限緩和 - cpprefjp C++日本語リファレンス
これによって何が変わるのでしょうか。
イテレータの思想の違い
STLのイテレータはメモリはコンテナが持ってイテレータは最小限の値のみ持つという思想で作られていました。
一方マイクロソフトの提供するAPIはイテレータ自体が終端の判断をする機能を持つことが多いです。
その思想の違いをこの制限緩和は扱いやすくしてくれます。
親プロセスの名前を取得するサンプル
#include <iostream> #include <optional> #include <Windows.h> #include <TlHelp32.h> struct SelfOperationTag {}; class ProcessEntryIterator { public: ProcessEntryIterator() { processEntries = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (processEntries == INVALID_HANDLE_VALUE) { result = false; return; } processEntry.dwSize = sizeof(PROCESSENTRY32); result = Process32First(processEntries, &processEntry); } ~ProcessEntryIterator() { CloseHandle(processEntries); } const PROCESSENTRY32& operator*() { return processEntry; } void operator++() { result = Process32Next(processEntries, &processEntry); } operator bool() const { return result; } private: HANDLE processEntries; PROCESSENTRY32 processEntry; bool result; }; bool operator!=(const ProcessEntryIterator& iterator, SelfOperationTag) { return iterator; } class Toolhelp32Snapshot { public: auto begin() const { return ProcessEntryIterator(); } auto end() const { return SelfOperationTag(); }; static std::optional<PROCESSENTRY32> Find(DWORD processID) { for (const auto& processEntry : Toolhelp32Snapshot()) { if (processEntry.th32ProcessID == processID) { return processEntry; } } return std::nullopt; } }; int main() { auto currentProcessID = GetCurrentProcessId(); auto currentProcess = Toolhelp32Snapshot::Find(currentProcessID); if (currentProcess) { auto parentProcess = Toolhelp32Snapshot::Find(currentProcess->th32ParentProcessID); if (parentProcess) { std::wcout << parentProcess->szExeFile << std::endl; } } }
煩雑なエラーハンドリングで抜けが出てしまいにくいのではないでしょうか。下記サイトでは現実的には起こらないでしょうがProcess32Firstのエラーハンドリングが抜けています。
モジュールの列挙 (PSAPI)
正しくハンドリングしてgotoやdo whileが出てくるのも辛いものです。
Windows-classic-samples/shared.c at master · Microsoft/Windows-classic-samples · GitHub