Is it possible to exclude an instance of a class of type RAII "anonymously"?

Suppose I have a C ++ class in RAII style:

class StateSaver { public: StateSaver(int i) { saveState(); } ~StateSaver() { restoreState(); } }; 

... for use in my code:

 void Manipulate() { StateSaver save(1); // ...do stuff that modifies state } 

... The goal is to enter into some state, do something, and then leave this state when I leave this area. Is there a way to prevent this typo from compiling (or warning, or complaining somehow so that I can spot an error)?

 void Manipulate() { StateSaver(1); // ruh-roh, state saved and immediately restored! // ...do stuff that modifies state } 

I don't know anything about C ++ itself, which I could use to prevent this, but that does not mean that it does not exist. If there was nothing in C ++, extensions specific to the compiler are permissible. What interests me most is everything related to gcc and msvc (once icc, ideas for other compilers are welcome, but less likely to be useful), so hacking for any of them would be useful (abstracted into the corresponding macro definitions # ifdef'd, of course )

+7
c ++ gcc visual-c ++ icc raii
source share
4 answers

I actually had to fine-tune my solution in several ways from the Waldo option, but in the end I got a macro:

 class GuardNotifier { bool* notified; public: GuardNotifier() : notified(NULL) { } void init(bool* ptr) { notified = ptr; } ~GuardNotifier() { *notified = true; } }; class GuardNotifyReceiver { bool notified; public: GuardNotifyReceiver() : notified(false) { } void init(const GuardNotifier& notifier) { const_cast<GuardNotifier&>(notifier).init(&notified); } ~GuardNotifyReceiver() { assert(notified); } }; class StateSaver { GuardNotifyReceiver receiver; public: StateSaver(int i, const GuardNotifier& notifier = GuardNotifier()) { receiver.init(notifier) saveState(); } ~StateSaver() { restoreState(); } }; 
+3
source share

I'm not sure if you can do anything at compile time. To check the runtime, you can do the following:

 struct SaveMatrix { SaveMatrix(const SaveMatrix& that) { assert(this == &that); glPushMatrix(); } ~SaveMatrix() { glPopMatrix(); } }; 

This requires the client to write:

 SaveMatrix sm(sm); 

and there is no way to do the same for the temporary without binding to the identifier (at which point it does not differ from the automatic variable).

+9
source share

SaveMatrix save(); also does not define the object. He declares a function.

You can do very little so that others (or yourself, FTM) cannot do anything else they want. The only thing I can think of is not to write the code itself, but to write a macro.

 #define SAVE_MATRIX SaveMatrix save ## __LINE__ 

However, this is pretty ugly. OTOH, it breaks the error at compile time.

+6
source share

A class can never determine whether it was created as a temporary (SaveMatrix ()) or as a variable (SaveMatrix save;). I think the best way to stop a programmer doing this without a stack or macros is to force a member function call after construction, for example:

 class RAII { public: bool valid; RAII() : valid(false) { cout << "RAII ctor" << endl; } void Do() { valid = true; } ~RAII() { assert(valid); cout << "RAII dtor" << endl; } }; 

This works as follows:

 { // Intended use RAII raii; raii.Do(); cout << "Some task" << endl; } { // Woops: forgot Do() RAII raii; cout << "Some task" << endl; } { // Woops: forgot Do() RAII(); cout << "Some task" << endl; } { // Programmer shot self in foot, hopefully the act of typing this would make them realise that RAII().Do(); cout << "Some task" << endl; } 
+1
source share

All Articles