conditional statement + automatic clean-up in preprocessor command

Started by
7 comments, last by floatingwoods 10 years, 4 months ago

Hello,

I wish to have a conditional statement, followed immediately by an object instanciation that will automatic clean-up at the end of a scope, a little bit similar to following example:


if (conditionRealized)
{
    // do something
}

which effectively would translate into something like:


if (conditionRealized)
{
    DummyObject dummy(initializationType);
    // do something
}

in above example, the destructor of dummy can automatically clean-up various things.

I have to place such a construct into several hundreds of functions, and I wish to simplify the task with a preprocessor command, so that I will be able to write:


IF_CONDITION_REALIZED_THEN
{
    // do something
}

but above construct does obviously not work, since the scope comes after the preprocessor command.

I could use a preprocessor like:


#define IF_CONDITION_REALIZED_THEN if(conditionRealized) { DummyObject dummy(initializationType);

in order to write my code like:


IF_CONDITION_REALIZED_THEN
    // do something
}

but my code editor doesn't like this (puts wrong indents), and it looks ugly.

Any idea?

Or, to present my problem in a different light:

I have a condition, that if passed, needs to make sure something is executed at the end of the scope, similar to this example:


if (canLockOtherThreads())
{
    // do something
    unlockOtherThreads();
}
Advertisement

You can do that with for() loop that does only single cycle:


#define IF_CONDITION_REALIZED_THEN for(DummyObject dummy(initializationType); conditionRealized; conditionRealized = false)

though it'll modify conditionRealized variable.

If you can do the cleanup with a free function instead of a destructor, here's one possibility:


#include <iostream>

#define IF_WITH_CLEANUP(X) for (bool dummy_boolean = (X); dummy_boolean; unlockOtherThreads(), dummy_boolean = false)

void unlockOtherThreads() {
  std::cout << "Unlocked!\n";
}

int main() {
  bool condition = true;
 
  IF_WITH_CLEANUP (condition)
    std::cout << "Write something\n";
}

Although I would hate you if you did something like that in code that I have to work with. smile.png

EDIT: Sooner or later someone will write a `continue' or `break' inside the conditional block and we'll have some fun debugging it.

Thanks to both of you, that's briliant!

Here's another slightly less nasty way to do it. It involves modifying (or wrapping) the auto destructing class so it holds the result of the condition, and declaring a variable inside the if statement:


class hack
{
private:
    bool m_cond;

public:
    hack(bool cond, int x) : m_cond(cond) { cout << "hack()" << x << endl; }
    ~hack() { cout << "~hack()" << endl; }

    operator bool() { return m_cond; }
};

#define HACKY_IF(cond, value) if (hack h = hack(cond, value))
 
int main()
{
    HACKY_IF(true, 42)
    {
        cout << "bar" << endl;
    }

    cout << "main end" << endl;
}

This also works:


#include <iostream>
using namespace std;

class Test
{
	public:
	Test(bool condition) : condition(condition)
	{
		if(condition)
		{
			std::cout << "if(condition) special init needs" << std::endl;
		}
	}
	
	~Test()
	{
		if(condition)
		{
			std::cout << "if(condition) special cleanup needs" << std::endl;
		}
	}
	
	operator bool() { return condition; }
	
	private:
	bool condition = false;
};

#define DoIf(cond) if(Test DoIf_test = Test(cond))

int main()
{
	std::cout << "Start of main" << std::endl;
	
	DoIf(true)
	{
		std::cout << "Inside condition A" << std::endl;	
	}
	
	DoIf(false)
	{
		std::cout << "Inside condition B" << std::endl;	
	}
	
	std::cout << "End of main" << std::endl;	
	
	return 0;
}

This is legal, afaik, but I'm not sure if the lifetime of assignments within conditionals is standardized.

Compilable example

Some static code analyzers will complain about assignments within if() statements as warnings, because it'll think you're actually wanting if(i == 0) but are accidentally using if(i = 0).

[Edit:] Uh, ninja'd by almost an hour. rolleyes.gif I had to refine and test my work several times before I got it working, initially going the lambda route which, while functional, had too many limitations and syntax messiness.

Why not just put that 'special condition' in the object destructor instead? blink.png

Or just code a normal function for that???

Just a note that all the above suggestions (the for loop back, etc.) are not exception safe.

As a general rule, I'd advise against this kind of macro. It's non-idiomatic, error prone and difficult to debug.

C++ already has a perfectly valid cleanup mechanism in RAII. Trust me, saving a bit of typing is just not worth it

Edit: oops, missed servants post. That is exception safe, still wouldn't use the macro though.
if you think programming is like sex, you probably haven't done much of either.-------------- - capn_midnight

A lot of good ideas, thanks a lot to all of you!

This topic is closed to new replies.

Advertisement