17

私はC++のアマチュアです。私はいくつかのWin32APIコードを書いていますが、ハンドルと奇妙に複合的に割り当てられたオブジェクトがたくさんあります。だから私は疑問に思っていました-リソース管理を簡単にするラッパークラスはありますか?

たとえば、データをロードしたい場合は、でファイルを開いてCreateFile()を取得しHANDLEます。それが終わったら、私はそれを呼び出す必要がCloseHandle()あります。ただし、かなり複雑なロード関数の場合、例外は言うまでもなく、数十の出口ポイントが考えられます。

CloseHandle()したがって、実行がスコープを離れると自動的に呼び出される、ある種のラッパークラスでハンドルをラップできれば素晴らしいと思います。さらに良いことに、参照カウントを実行できるので、他の関数に出し入れすることができ、最後の参照がスコープを離れたときにのみリソースを解放します。

コンセプトはシンプルですが、標準ライブラリにそのようなものはありますか?ちなみに、私はVisual Studio 2008を使用していますが、Boostなどのサードパーティのフレームワークをアタッチしたくありません。

4

8 に答える 8

12

自分で書いてください。ほんの数行のコードです。非常に単純なタスクなので、一般的な再利用可能なバージョンを提供する価値はありません。

struct FileWrapper {
  FileWrapper(...) : h(CreateFile(...)) {}
  ~FileWrapper() { CloseHandle(h); }

private:
  HANDLE h;
};

汎用バージョンが何をしなければならないかを考えてください。関数の任意のペアとそれらに対する引数の数を指定できるように、パラメーター化可能である必要があります。このようなオブジェクトをインスタンス化するだけで、上記のクラス定義と同じ数のコード行が必要になる可能性があります。

もちろん、C ++ 0xは、ラムダ式を追加することでバランスをいくらか傾ける可能性があります。2つのラムダ式を汎用ラッパークラスに簡単に渡すことができるため、C ++ 0xのサポートが開始されると、そのような汎用RAIIクラスがBoostなどに追加されることがあります。

しかし、現時点では、必要なときにいつでも自分でロールする方が簡単です。

参照カウントの追加については、反対することをお勧めします。参照カウントはコストがかかり(突然、ハンドルを動的に割り当てる必要があり、すべての割り当てで参照カウンターを維持する必要があります)、正しく理解するのは非常に困難です。ねじ山のある環境で、微妙な競合状態が発生しているエリアです。

参照カウントが必要な場合は、次のようにしboost::shared_ptr<FileWrapper>ます。カスタムアドホックRAIIクラスをでラップしますshared_ptr

于 2010-03-12T14:24:38.103 に答える
3

基本的に、fstreamこれはファイルハンドルに適したC++ラッパーです。これは標準の一部であり、移植性があり、十分にテストされており、オブジェクト指向の方法で拡張可能であることを意味します。ファイルリソースの場合、これは優れた概念です。

ただし、fstreamファイルに対してのみ機能し、一般的なハンドル、つまりスレッド、プロセス、同期オブジェクト、メモリマップトファイルなどに対しては機能しません。

于 2010-03-12T14:16:44.417 に答える
3

これらのラッパーはATLと呼ばれます。

ハンドルがイベントなどの場合は、CHandleクラスを使用してください。

ハンドルがファイルの場合は、CAtlFileから派生したものを使用し、CreateFileやReadFileなどのAPIをラップします。

ATLにCAtlFileMapping<T>は他にも便利なラッパーがあり、メモリマップトファイルのRAIIラッパーでCPathあり、パス処理のためにshell32APIをラップします。

ATLは大規模なライブラリですが、ファイル、文字列、コレクションなどの低レベルのものは分離されています。これらはすべてのWin32アプリで使用できます。はヘッダーのみであり、何かとリンクしたり、MFCやCRTなどの追加のDLLを配布したりする必要はありません。コードは、WinAPI呼び出しにコンパイルされ、正常に機能します。

それらはVS2003または2005でMFCから分割されましたが、覚えていません。つまり、VisualStudio2008には間違いなくそれらがあります。ただし、注意点が1つあります。ただし、フリーウェアバージョンのVSを使用している場合は、2015年以降である必要があります。

于 2019-06-28T16:35:14.027 に答える
1

これは、「Windows via C / C ++」のEnsureCleanupコードに基づくものです:http: //www.codeproject.com/KB/cpp/template2003.aspx

于 2010-03-12T14:34:07.803 に答える
0

MFCにはいくつかの適切なプリミティブ(たとえばCFileを見てください)がありますが、標準ライブラリはありません。

于 2010-03-12T14:13:29.403 に答える
0

Visual C ++ 2008は、機能パックを介してTR1をサポートし、TR1にはshared_ptrが含まれています。私はこれを使用します-これは非常に強力なスマートポインタクラスであり、要求しているタイプのリソース管理を行うために一般化することができます。

TR1は、事実上、標準の拡張です。まだ公式には「プレスタンダード」だと思いますが、事実上、ロックダウンされていると見なすことができます。

于 2010-03-12T14:21:23.270 に答える
0

標準ライブラリには何もないと思います。また、共有ポインタ(boostのように)を使用できるかどうかも疑問です(HANDLEではなくHANDLEへのポインタを期待しているため)。

スコープガードのイディオムに従って(そして、必要に応じてテンプレート/関数ポインターなどを利用して)、自分で作成するのは難しいことではありません。

于 2010-03-12T14:40:57.943 に答える
0
template <typename Traits>
class unique_handle
{
    using pointer = typename Traits::pointer;

    pointer m_value;

    auto close() throw() -> void
    {
        if (*this)
        {
            Traits::close(m_value);
        }
    }

public:

    unique_handle(unique_handle const &) = delete;
    auto operator=(unique_handle const &)->unique_handle & = delete;

    explicit unique_handle(pointer value = Traits::invalid()) throw() :
        m_value{ value }
    {
    }

    unique_handle(unique_handle && other) throw() :
        m_value{ other.release() }
    {
    }

    auto operator=(unique_handle && other) throw() -> unique_handle &
    {
        if (this != &other)
        {
            reset(other.release());
        }

        return *this;
    }

    ~unique_handle() throw()
    {
        close();
    }

    explicit operator bool() const throw()
    {
        return m_value != Traits::invalid();
    }

    auto get() const throw() -> pointer
    {
        return m_value;
    }

    auto get_address_of() throw() -> pointer *
    {
        ASSERT(!*this);
        return &m_value;
    }

    auto release() throw() -> pointer
    {
        auto value = m_value;
        m_value = Traits::invalid();
        return value;
    }

    auto reset(pointer value = Traits::invalid()) throw() -> bool
    {
        if (m_value != value)
        {
            close();
            m_value = value;
        }

        return static_cast<bool>(*this);
    }

    auto swap(unique_handle<Traits> & other) throw() -> void
    {
        std::swap(m_value, other.m_value);
    }
};

template <typename Traits>
auto swap(unique_handle<Traits> & left,
    unique_handle<Traits> & right) throw() -> void
{
    left.swap(right);
}

template <typename Traits>
auto operator==(unique_handle<Traits> const & left,
    unique_handle<Traits> const & right) throw() -> bool
{
    return left.get() == right.get();
}

template <typename Traits>
auto operator!=(unique_handle<Traits> const & left,
    unique_handle<Traits> const & right) throw() -> bool
{
    return left.get() != right.get();
}

template <typename Traits>
auto operator<(unique_handle<Traits> const & left,
    unique_handle<Traits> const & right) throw() -> bool
{
    return left.get() < right.get();
}

template <typename Traits>
auto operator>=(unique_handle<Traits> const & left,
    unique_handle<Traits> const & right) throw() -> bool
{
    return left.get() >= right.get();
}

template <typename Traits>
auto operator>(unique_handle<Traits> const & left,
    unique_handle<Traits> const & right) throw() -> bool
{
    return left.get() > right.get();
}

template <typename Traits>
auto operator<=(unique_handle<Traits> const & left,
    unique_handle<Traits> const & right) throw() -> bool
{
    return left.get() <= right.get();
}

struct null_handle_traits
{
    using pointer = HANDLE;

    static auto invalid() throw() -> pointer
    {
        return nullptr;
    }

    static auto close(pointer value) throw() -> void
    {
        VERIFY(CloseHandle(value));
    }
};

struct invalid_handle_traits
{
    using pointer = HANDLE;

    static auto invalid() throw() -> pointer
    {
        return INVALID_HANDLE_VALUE;
    }

    static auto close(pointer value) throw() -> void
    {
        VERIFY(CloseHandle(value));
    }
};

using null_handle = unique_handle<null_handle_traits>;
using invalid_handle = unique_handle<invalid_handle_traits>;
于 2016-05-10T11:09:41.613 に答える