4

I've a class like this:

class ScopedLock {
public:
    ScopedLock (Locker *lock) { /*...*/ }
    ~ScopedLock () { /*...*/ }
};

Normally it's called like (this will call the constructor/destructor of ScopedLock at the correct place) :

{
    ScopedLock l(&locker);
    // ...
}

I've accidentally called it like:

{
    ScopedLock(&locker);
    // ...
}

What is the name for such a "thing"? Unused anonymous local variable?

Is there a possibility to prevent this? Is there a compiler warning available for such a "thing"?

powerpete
  • 2,663
  • 2
  • 23
  • 49
  • 5
    You 've created an _unnamed temporary_ of type `ScopedLock` that lives briefly and then dies at the `;`. – Ron Jul 12 '18 at 10:52
  • 3
    _"Normally it's called like: ..."_ So you intended a function forward declaration there? Be aware of the _most vexing parse_! – πάντα ῥεῖ Jul 12 '18 at 10:54
  • 1
    Also I don't think there should be a warning generated, there might be cases, where such is done intentionally. – πάντα ῥεῖ Jul 12 '18 at 10:57
  • 3
    I would have expected `[[nodiscard]] ScopedLock (...) { ...}` to issue the wanted warning, but instead, I got a warning that it cannot apply the attribute to constructor :-/ – Jarod42 Jul 12 '18 at 10:57
  • Amazing video about this here: http://www.youtube.com/watch?v=lkgszkPnV8g&t=29m40s – Fantastic Mr Fox Jul 12 '18 at 11:16
  • Maybe [this question](https://stackoverflow.com/questions/47602539/emulate-c-sharp-lock-statement-in-c) is also interesting in this context. – Jodocus Jul 12 '18 at 12:15

2 Answers2

4

You have created an unnamed temporary / nameless temporary object of type ScopedLock that lives briefly and then dies at the ;. The compiler does not issue a warning as it assumes you are doing something useful with it. It does not go into a ctor body to inspect if that might be the case. For example you want to create a temporary where your constructor might do some work:

ScopedLock() {
    // do some work
}

You can't force a compiler to show a warning for such use-cases and there is no such flag in GCC.

The following SO posts can prove beneficial:

Ron
  • 14,674
  • 4
  • 34
  • 47
3

You can make a construction function marked as nodiscard that should be invoked instead of constructor.

#include <iostream>

class ScopedLock final
{
    private: ScopedLock(int, int) {std::cout << "constructed" << std::endl;}
    private: ScopedLock(void)                            = delete;
    private: ScopedLock(ScopedLock const &)              = delete;
    private: ScopedLock(ScopedLock &&)                   = delete;
    private: ScopedLock & operator =(ScopedLock const &) = delete;
    private: ScopedLock & operator =(ScopedLock &&)      = delete;

    public: [[nodiscard]] static ScopedLock
    construct(int x, int y)
    {
        return ScopedLock{x, y};   
    }
};

int main()
{
    ScopedLock(12, 123); // Error
    ScopedLock::construct(12, 123); // Warning
    auto lock(ScopedLock::construct(12, 123)); // Ok
}

online compiler

user7860670
  • 35,849
  • 4
  • 58
  • 84