Help us understand the problem. What is going on with this article?

VS2013でもstd::error_codeとかstd::system_category()を使いたい

More than 3 years have passed since last update.

はじめに

Visual Studio も最近はだいぶC++標準への準拠が進んでいて、Visual Studio "15" Preview 5ではC++14のconstexprも使えるそうですね。

しかしまだVisual Studio 2013のサポートは切れない、というプロジェクトも多いハズ。

ところで、C++11でstd::error_code, std::error_category, std::system_category(), std::system_errorといったクラス・関数が追加され、Win32APIのエラーコードの文字列化にFormatMessageを自力で呼び出さなくて良くなりました。

FormatMessageを呼ばなくていい素晴らしい世界
using std::system_category;
using std::system_error;
const auto er = RegOpenKeyEx(parent_key_handle, sub_key_root, 0, r, &this->key);
if (ERROR_SUCCESS != er) {
    throw system_error(std::error_code(er, system_category()), "RegOpenKeyEx:(" + std::to_string(er) + ')');
}

でもね、それVS2013では使えないんだ

残念ながらVS2013では実装が途中で使い物になりません。

いや、まあVS2015でもぶっ壊れてるじゃねーか!という話もありますが
VS2015のstd::error_categoryが奇想天外な件について
規格に沿っていないというだけで動作的には期待したものですしお寿司。

じゃあ自作しよう

#include <Windows.h>
#include <string>
#include <stdexcept>
#include <system_error>
#if defined(_MSC_VER) && _MSC_VER < 1900
std::string format_message(DWORD lasterr) {
    char* buf = nullptr;
    const DWORD len = FormatMessageA(
        FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY,
        nullptr,
        lasterr,
        LANG_NEUTRAL,
        reinterpret_cast<LPSTR>(&buf),
        0,
        nullptr
    );
    DWORD i = (len < 3) ? 0 : len - 3;
    for (; '\r' != buf[i] && '\n' != buf[i] && '\0' != buf[i]; i++);//改行文字削除
    buf[i] = '\0';
    std::string ret;
    try{
        ret = buf;//エラーメッセージをコピー
    }
    catch(...){//ここで例外を投げるよりはエラーメッセージなしのほうが良いので握りつぶす
    }
    LocalFree(buf);//FormatMessageAでFORMAT_MESSAGE_ALLOCATE_BUFFERを指定したので必ず開放
    return ret;
}
using std::error_category;
class system_error_category_c : public error_category { // categorize an operating system error
public:
    system_error_category_c() : error_category() {}
    virtual const char *name() const { return "system"; }
    virtual std::string message(int ec) const
    {
        try {
            return format_message(ec);
        }
        catch (...) {
            return "unknown error";
        }
    }
};
namespace detail {
    template<typename T> T& put_on_static_storage() {
        static T storage;
        return storage;
    }
}
error_category& system_category() {
    return detail::put_on_static_storage<system_error_category_c>();
}
using std::runtime_error;
class system_error : public runtime_error
{
public:
    system_error(std::error_code ec, const std::string& m)
        : ec_(ec), runtime_error((m.empty()) ? ec.message() : m + ": " + ec.message())
    {}
    system_error(std::error_code ec) : system_error(ec, "") {}
    system_error(std::error_code ec, const char *m) : system_error(ec, std::string(m)) {}
    system_error(int e, const error_category& erct) : system_error(e, erct, "") {}
    system_error(int e, const error_category& erct, const std::string& m) : system_error(std::error_code(e, erct), m) {}
    system_error(int e, const error_category& erct, const char *m) : system_error(e, erct, std::string(m)) {}
    const std::error_code& code() const { return ec_; }
private:
    std::error_code ec_;
};
#else
using std::system_category;
using std::system_error;
#endif

使用例

https://github.com/yumetodo/windows_registry_manager/blob/master/src/registry_key.cpp

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした