2015-11-17 8 views
6

Einige Leute warnen, dass Sperren falsch verwendet durch Schreiben sein kann:Ist es möglich, temporäre Variablen in C++ explizit zu instanziieren?

std::unique_lock<std::mutex>(mutex); 

statt der folgenden richtige Aussage:

std::unique_lock<std::mutex> lock(mutex); 

D.h. Erstellen Sie eine unbenannte temporäre Variable anstelle einer lokalen Variablen. Die temporäre Variable würde sofort zerstört werden und den Mutex vorzeitig freigeben.

Siehe zum Beispiel gperftools (line 321-324) header:

// Catch bug where variable name is omitted, e.g. MutexLock (&mu); 
#define MutexLock(x) COMPILE_ASSERT(0, mutex_lock_decl_missing_var_name) 
#define ReaderMutexLock(x) COMPILE_ASSERT(0, rmutex_lock_decl_missing_var_name) 
#define WriterMutexLock(x) COMPILE_ASSERT(0, wmutex_lock_decl_missing_var_name) 

Dieses Makro wieder Fälle eine solche Verwendung zu schützen geschrieben wird.

Aber kann es immer noch passieren? Offenbar ist ein kürzliches genug GCC oder Klappern werden Fehler in diesem Fall produzieren:

#include <iostream> 

class Mutex {}; 

class Lock { 
public: 
    explicit Lock(Mutex */* dummy */) { std::cout << __PRETTY_FUNCTION__ << std::endl; } 
    ~Lock() { std::cout << __PRETTY_FUNCTION__ << std::endl; } 
}; 

int main() { 
    Mutex mutex; 
    { 
    Lock l(&mutex); 
    } 
    { 
    Lock(&mutex); // This line does not compile. 
    } 
    return 0; 
} 

Und den Fehler:

g++ foo.cpp 
foo.cpp:17:11: error: declaration of reference variable 'mutex' requires an initializer 
    Lock(&mutex); 
      ^~~~~ 
1 error generated. 

Könnte jemand einen repro Fall zeigen, wo ein solcher Makro einen echten Fehler fangen würde? Ich konnte bis jetzt noch nicht kommen.

+1

Möglicherweise verwandte: http://stackoverflow.com/questions/914861/disallowing-creation-of-the -temporary-objects – BenC

Antwort

4

Sie werden tatsächlich durch die Disambiguierungsregel für Dinge-die-kann-sein-Deklarationen gespeichert (sie werden als Deklarationen, nicht als Ausdrücke analysiert), gekoppelt mit der Regel, die Referenzen benötigt, um initialisiert zu werden.

Es wird Ihnen hier nicht sparen:

std::mutex m; 
int main(){ 
    std::unique_lock<std::mutex>(m); // m is a local default-constructed unique_lock 
} 

oder hier:

struct C { Mutex m; } c; 
int main() { 
    Lock(&c.m); // Constructs and destroys a temporary lock. 
} 
+0

Für das erste Beispiel ist es sehr verwirrend, dass wenn std :: mutex innerhalb von main ist, wenn nicht kompiliert wird, aber wenn der Mutex außerhalb ist. Könnten Sie näher erläutern, welche Art von Mustern hier problematisch sind? –

+0

@ThomasMoulard 'std :: unique_lock (m);' ist genau äquivalent zu 'std :: unique_lock m;' da es als Deklaration analysiert wird. Es sollte jetzt ziemlich offensichtlich sein, warum es nicht kompiliert, wenn der Mutex in 'main' ist. –

+0

ok Ich fühle mich jetzt blöd;) danke! –

Verwandte Themen