Come around limitation of CSingleLock don't accept NULL The CSyncObject object in CSingleLock constructor can't be NULL but I want it to work with NULL because I need to use this nest. 

BOOL CADODatabase::Open(LPCTSTR lpstrConnection, LPCTSTR lpstrUserID, LPCTSTR lpstrPassword)
{
    CString database = GetSourceDatabase( lpstrConnection, NULL );

    // get the appropriate critical section based on database
    g_dbCriticalSection = GetDbCriticalSection( database );

    if( g_dbCriticalSection) // it can be NULL
    {
        g_dbCriticalSection-&gt;Lock(); 
    }

    // more code,  have to unlock() manually in multiple exits!
}


As can be seen, I need to lock() and then unlock() manually at all exit points because its in a nest.

i wrote a class to make CSingleLock work with NULL, my new code looks like this:

BOOL CADODatabase::Open(LPCTSTR lpstrConnection, LPCTSTR lpstrUserID, LPCTSTR lpstrPassword)
{
    CString database = GetSourceDatabase( lpstrConnection, NULL );

    // get the appropriate critical section based on database
    g_dbCriticalSection = GetDbCriticalSection( database );

    CSingleLockEx lock( g_dbCriticalSection, TRUE );

    // eliminates the need to unlock() manually, works like CSingleLock
}


My new class is here:

class CSingleLockEx
{
public:
    CSingleLock* _singleLock;

    CSingleLockEx(CSyncObject* pObject, BOOL bInitialLock = FALSE):
    _singleLock(NULL)
    {
        if (pObject)
            _singleLock = new CSingleLock(pObject, bInitialLock);

    }
    ~CSingleLockEx()
    {
        if (_singleLock)
            delete _singleLock;
    }
};


Since it has to do with critical section, I thought I will put it for review if I have missed anything.
Sure, that seems fine.


Obviously you should be using std::unique_ptr&lt;CSingleLock&gt; (and std::make_unique) instead of raw new and delete.
If you have access to C++17, Folly, or Boost, consider using std::optional&lt;CSingleLock&gt; to eliminate the heap allocation.
If you're not using unique_ptr, you might want to =delete your copy constructor and copy assignment operator (or in C++03, make them private), to ensure that nobody accidentally creates a copy of your object — which if they did would lead to a double-free.




You've also made your member variable _singleLock public, presumably by accident. If you actually want it to be public, consider giving it a more user-friendly name. It's best to keep it private, though.



A simpler approach would be to create a dummy lock, which (assuming either CSingleLock or CMutex is immovable) would actually fix the copyability problem as well.

class CSingleLockEx
{
    CMutex dummy_;
    CSingleLock lk_;
public:
    CSingleLockEx(CSyncObject *obj, bool initialLock = false) :
        lk_((obj ? *obj : dummy_), initialLock)
    {}
};


This way you end up locking something either way (and unlocking something in the destructor as well), but at least when obj==nullptr the "something" you're locking will definitely be uncontended. So I wouldn't expect a noticeable performance hit.