5

次のように宣言されたインターフェイスがあります。

    #if defined _WIN32 || _WIN64
        typedef CRITICAL_SECTION MutexHandle;
    #else
        typedef pthread_mutex_t MutexHandle;
    #endif

    class IMutex
    {
    public:
        enum MutexState
        {
            UNLOCKED = 0,
            LOCKED
        };

        virtual ~IMutex() { }

        virtual int32_t Lock() = 0;
        virtual int32_t Unlock() = 0;

        virtual const MutexState& GetMutexState() const = 0;
        virtual MutexHandle& GetMutexHandle() = 0;
    };

問題は、CRITICAL_SECTION の定義に windows.h を含める必要があることです。

#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#undef WIN32_LEAN_AND_MEAN

しかし、これにより、ヘッダーに含まれる可能性のあるインターフェイスを使用している他のユーザーに問題が発生することはありませんか?

windows.h 全体をインクルードせずに typedef を宣言するにはどうすればよいですか?

ありがとう

4

4 に答える 4

8

実装の詳細が他のコードに漏れるのを防ぐ典型的な方法は、Pimpl イディオムを使用することです。アイデアは、クラスに実際の実装へのポインターを単純に含めることです。実際の実装は .cpp ファイルに存在するため、クラスのユーザーの名前空間を汚染することなく、必要なものをすべて含めることができます。

ヘッダー ファイル内:

#include <memory>  // for std::unique_ptr

class Mutex {
  public:
    Mutex();
    ~Mutex();
    void Lock();
    // ...
  private:
    class Impl;
    std::unique_ptr<Impl> m_pimpl;
};

次に、実装 (.cpp) クラスで:

#include <windows.h>  // nobody else sees this

class Mutex::Impl {
  public:
    Impl() {
      ::InitializeCriticalSection(&m_cs);
    }
    ~Impl() {
      ::DeleteCriticalSection(&m_cs);
    }

    void Lock() {
      ::EnterCriticalSection(&m_cs);
    }

    // etc.

  private:
    CRITICAL_SECTION m_cs;
};

// This maps the externally visible Mutex methods to the
// ones in the Implementation.
Mutex::Mutex() : m_pimpl(new Mutex::Impl()) {}
Mutex::~Mutex() {}
void Mutex::Lock() { m_pimpl->Lock(); }

実装全体を #ifdef ブロックまたは個別の .cpp ファイル (たとえば、mutex_win.cpp、mutex_posix.cpp など) に配置して、ビルドのタイプに適したものを使用することができます。

一般に、Pimpl Idiom には追加のポインター逆参照が必要ですが、仮想メソッド ソリューションにも必要です。

于 2012-09-13T00:50:20.163 に答える
4

おそらく次のように、コードパスの分離を少し粗くすることをお勧めします。

struct WinMutex;
struct PTMutex;

#ifdef WIN32

typedef WinMutex Mutex;

#include <windows.h> // or whatever

struct WinMutex
{
    CRITICAL_SECTION cs;
    void lock()   { /* lock it */ }
    void unlock() { /* unlock it */ }
};

#else

typedef PTMutex Mutex;

#include <pthread.h>

struct PTMutex
{
    pthread_mutex_t m;
    PTMutex() { pthread_mutex_init(&m); }
    ~PTMutex() { pthread_mutex_destroy(&m); }
    void lock() { pthread_mutex_lock(&m); }
    void unlock() { pthread_mutex_unlock(&m); }
}

#endif

そうすれば、個々のクラスの検査とリファクタリングが簡単になり、プラットフォームに依存する実装も取得できます。または、Windows 用の pthreads 実装が見つかった場合は、両方を同時に使用することもできます。

于 2012-09-12T21:00:10.077 に答える
2

根本的な問題は、オペレーティングシステム固有のタイプを非オペレーティング固有のコードに公開していることだと思います。

必要に応じて、1つの解決策は、GetMutexHandle関数をインターフェイスから除外IMutexし、2つのサブインターフェイスに含めることIMutexWin32ですIMutexPosixIMutexWin32インターフェースを具体的に要求したコードに対してのみインターフェースを宣言し、そのようなコードにを含めるように要求することができますWindows.h。とにかくGetMutexHandle、Windowsで実際に使用するコードはすべて必要になります。Windows.h

GetMutexHandleまたは、 OS固有のサブインターフェイスを使用して、戻り値を個別のインターフェイスクラスにすることもできます。

同じテーマのマイナーな変形は、Windows.hが含まれているかどうかを検出し(#ifdef _WINDOWS_)、これを使用してWindows固有のサブインターフェイスを宣言するかどうかを決定することです。

すべての中で最も簡単な(しかし最も醜い)解決策は、GetMutexHandlevoidへのポインターを返し、呼び出し元がそれを適切にキャストすることを信頼することです。

于 2012-09-12T21:39:49.980 に答える
2

windows.h へのヘッダー依存を完全に回避したい場合はCRITICAL_SECTION、windows.h の既存の宣言と一致するように前方宣言する必要があります。使用している windows.h のバージョンでこれが機能することを確認する必要がありますが、これは機能するはずです。

extern "C"
{
    typedef struct _RTL_CRITICAL_SECTION RTL_CRITICAL_SECTION;
    typedef RTL_CRITICAL_SECTION CRITICAL_SECTION;
}
于 2012-09-14T04:04:32.830 に答える