CRITICAL_SECTION and avoid turning on windows.h?

I have an interface declared as follows:

#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; }; 

The problem is that I need to enable windows.h to define CRITICAL_SECTION;

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

but can this heading include problems with others using the interface?

How can I declare my typedef without having to include the entire windows.h file?

thanks

+4
source share
4 answers

A typical way to prevent implementation details from leaking into other code is to use the Pimpl Idiom. The idea is for your class to simply contain a pointer to a real implementation. Since the real implementation is in the .cpp file, it can include everything it needs without polluting the user namespace of this class.

In the header file:

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

Then in the implementation class (.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(); } 

You can put the entire implementation in #ifdef blocks or in separate .cpp files (for example, mutex_win.cpp, mutex_posix.cpp, etc.) and just use the right one for your type of assembly.

In general, the Pimpl idiom requires additional dereference of the pointer, but also the solution to your virtual method.

+6
source

I would prefer a slightly coarser separation of the code paths, maybe like this:

 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 

This way, each individual class is simple enough for validation and refactoring, and you still get platform-specific implementations. Or, if you find a pthreads implementation for Windows, you can have both at the same time.

+4
source

I think the main problem is that you expose the type of a particular operating system to what might be inactive code.

One solution, depending on your needs, might be to exclude the GetMutexHandle function from the IMutex interface, but include it in two subinterfaces, IMutexWin32 and IMutexPosix say. You can declare the IMutexWin32 interface only for the code that specifically requested it, and require that code include Windows.h . Any code that actually uses GetMutexHandle for Windows needs Windows.h anyway.

Alternatively, you can make GetMutexHandle return a separate interface class with OS-specific subinterfaces.

A small version of the same topic will be to determine whether Windows.h is enabled ( #ifdef _WINDOWS_ ) or not, and use this to decide whether to declare a Windows-specific subinterface.

The simplest (but ugliest) solution for everyone is to make GetMutexHandle return a pointer to void and trust the caller to use it correctly.

+2
source

If you want to completely avoid the title dependency on windows.h, you need to forward declare CRITICAL_SECTION so that it matches the existing declaration in windows.h. You need to make sure that this works for the windows.h version that you are using, but this should work:

 extern "C" { typedef struct _RTL_CRITICAL_SECTION RTL_CRITICAL_SECTION; typedef RTL_CRITICAL_SECTION CRITICAL_SECTION; } 
+2
source

Source: https://habr.com/ru/post/1433893/


All Articles