Disallowing creation of the temporary objects

2020-01-26 09:58发布

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

CSingleLock(&m_criticalSection, TRUE);

Notice that it is creating an unnamed object of CSingleLock class and hence the critical section object gets unlocked immediately after this statement. This is obviously not what the coder wanted. This error was caused by a simple typing mistake. My question is, is there someway I can prevent the temporary object of a class being created at the compile time itself i.e. the above type of code should generate a compiler error. In general, I think whenever a class tries to do some sort of resource acquisition then the temporary object of that class should not be allowed. Is there any way to enforce it?

8条回答
smile是对你的礼貌
2楼-- · 2020-01-26 10:48

No, there is no way of doing this. Doing so would break almost all C++ code which relies heavily on creating nameless temporaries. Your only solution for specific classes is to make their constructors private and then always construct them via some sort of factory. But I think the cure is worse than the disease!

查看更多
劳资没心,怎么记你
3楼-- · 2020-01-26 10:48

Old question, but I have a couple of points to add.

By define a macro function with the same name as the class, you can trigger a static assertion with a helpful message when someone forgets the variable name. live here

class CSingleLock {
 public:
  CSingleLock (std::mutex*, bool) { }
};

// must come after class definition
#define CSingleLock(...) static_assert(false, \
    "Temporary CSingleLock objects are forbidden, did you forget a variable name?")

The macro won't match when there is a ariable name. However, this doesn't help in the case of uniform initialization; you can't catch CSingleLock{&m, true}. PfhorSlayer's answer works with uniform initialization so it is safer to use, at the cost of a more confusing error message. I would still reccomend that solution over mine. Unfortunately all these macro solutions fail when the type is in a namespace.


Another solution is to produce a compiler warning using [[nodiscard]]

class CSingleLock {
 public:
  [[nodiscard]] CSingleLock (std::mutex*, bool) { }
};

If you create a temporary clang will warn you saying:

warning: ignoring temporary created by a constructor declared with 'nodiscard' attribute [-Wunused-value]
  CSingleLock(&m, true);
  ^~~~~~~~~~~~~~~~~~~~~

GCC 9.2 seems to have a problem with [[nodiscard]] on constructors though. It still gives additional warnings if you don't use the result. The problem is fixed on head which at the time of writing this is gcc-10 20191217 on wandbox.

查看更多
登录 后发表回答