Disallowing creation of the temporary objects

后端 未结 8 897
南方客
南方客 2020-11-29 09:01

While debugging crash in a multithreaded application I finally located the problem in this statement:

CSingleLock(&m_criticalSection, TRUE);
相关标签:
8条回答
  • 2020-11-29 09:52

    Edit: As j_random_hacker notes, it is possible to force the user to declare a named object in order to take out a lock.

    However, even if creation of temporaries was somehow banned for your class, then the user could make a similar mistake:

    // take out a lock:
    if (m_multiThreaded)
    {
        CSingleLock c(&m_criticalSection, TRUE);
    }
    
    // do other stuff, assuming lock is held
    

    Ultimately, the user has to understand the impact of a line of code that they write. In this case, they have to know that they're creating an object and they have to know how long it lasts.

    Another likely mistake:

     CSingleLock *c = new CSingleLock(&m_criticalSection, TRUE);
    
     // do other stuff, don't call delete on c...
    

    Which would lead you to ask "Is there any way I can stop the user of my class from allocating it on the heap"? To which the answer would be the same.

    In C++0x there will be another way to do all this, by using lambdas. Define a function:

    template <class TLock, class TLockedOperation>
    void WithLock(TLock *lock, const TLockedOperation &op)
    {
        CSingleLock c(lock, TRUE);
        op();
    }
    

    That function captures the correct usage of CSingleLock. Now let users do this:

    WithLock(&m_criticalSection, 
    [&] {
            // do stuff, lock is held in this context.
        });
    

    This is much harder for the user to screw up. The syntax looks weird at first, but [&] followed by a code block means "Define a function that takes no args, and if I refer to anything by name and it is the name of something outside (e.g. a local variable in the containing function) let me access it by non-const reference, so I can modify it.)

    0 讨论(0)
  • 2020-11-29 09:57

    What about the following? Slightly abuses the preprocessor, but it's clever enough that I think it should be included:

    class CSingleLock
    {
        ...
    };
    #define CSingleLock class CSingleLock
    

    Now forgetting to name the temporary results in an error, because while the following is valid C++:

    class CSingleLock lock(&m_criticalSection, true); // Compiles just fine!
    

    The same code, but omitting the name, is not:

    class CSingleLock(&m_criticalSection, true); // <-- ERROR!
    
    0 讨论(0)
提交回复
热议问题