Inspired by this question. Suppose I have class Lock
with a default constructor and in some code I write the following statement:
Lock();
this will have the effect of creating a temporary object of class Lock
and immediately destroying it. Of course, creation could have some side effects and that would alter the program behavior, however that looks rather weird.
So my first guess is that such statements while completely valid from the language perspective are highly likely to contain a logical error.
Are there some valid usecases of the above statement? Are there some well-known and popular idioms that include such statements? Why would I want such statements in a correct program?
It doesn't look any weirder than a call to a void function named Lock
.
Not that I'm suggesting that you go around thinking of functions as just funny-named constructors (of whatever their return type is), but the syntax is intentionally similar.
I can't for the moment think of a good reason to create but not use a Lock
, but:
LockSession(lock);
has the same side-effects as you'd expect from:
acquire_and_then_immediately_release(lock);
As you say, this is very rarely what you want, so it might well look to the casual reader like an error. If for some odd reason it is what you want, and you want to avoid confusing people, you can do:
{
LockSession session(lock);
// release immediately
}
or for that matter:
void acquire_and_then_immediately_release(Lock &lock) {
LockSession(lock);
}
with the same effect and less chance of head-scratching whether that's really what you meant, or whether you've just made the common mistake of forgetting to supply a name and hence holding the lock for less time than you should.
Why would you want to acquire and then immediately release a lock? Probably because you're (ab)using it as a slightly peculiar semaphore. For example you could create a bunch of threads with a lock held, and if the first thing each thread does is this, then none of them will get past it until all the thread creation is done (plus anything else the parent wants the threads to be able to see) and the parent releases the lock. There are probably better examples out there of objects whose construction side-effects are significant.
Moving away from side-effects, another possibility is that if you want to check that a string is valid XML, you could write:
xml::dom::Document(mystring);
expecting an exception for invalid data. Again, the code would be more readable if you called a well-named function that does it. And constructing a DOM tree is not the most efficient way to validate XML. But if a class is what you already have then using it is the simplest thing that works.
I suppose the issue is that the name of a class is rarely descriptive of the side-effects of creating and destroying it. So a lone temporary will tend to look weird for that reason.
In order to get away from dangerous va_list
style variadics, I've written code that you call like this:
MyFunc() << a << b << c;
Where MyFunc
is implemented as a class with an operator <<
and ~MyFunc()
is responsible for doing the desired work. It's awkward to write the MyFunc
class, but once it's done, it works well.
So, yes, the pattern of instantiating a temporary object that only lasts for one line can be useful.
Similar syntax of creating a temporary is used many a times in template
metaprograms or boost
kind of libraries. They actually don't create temporary, but simulate its effect.
e.g. is_base_of
You can see temporary object syntax in the sizeof()
trick.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With