Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Do object arguments for dummy parameters get constructed?

Tags:

c++

Suppose a function template:

template <class T>
void foo(T /* dummy */) {...}

Suppose that foo is called like this:

foo(Widget());

Would a Widget object be constructed in this case?

This post asks a similar question about unused arguments (and arguments for dummy parameters are certainly unused). The replies suggest that, unless the function is called through a function pointer, the unused arguments will be optimized out by the compiler.

However, consider the following text in Section 2.5 of Modern C++ by Alexandrescu:

Now say there is a rule in your application: Objects of type Widget are untouchable legacy code and must take two arguments upon construction, the second being a fixed value such as -1. Your own classes, derived from Widget, don't have this problem.

...

In the absence of partial specialization of functions, the only tool available is, again, overloading. A solution would be to pass a dummy object of type T and rely on overloading:

template <class T, class U>
T* Create(const U& arg, T /* dummy */)
{
   return new T(arg);
}
template <class U>
Widget* Create(const U& arg, Widget /* dummy */)
{
   return new Widget(arg, -1);
}

Such a solution would incur the overhead of constructing an arbitrarily complex object that remains unused.

This suggests that the compilers are not smart enough to avoid the construction of the argument for the dummy parameter...

So, which is correct? If Alexandrescu is correct, then why doesn't this optimization happen?

like image 745
AlwaysLearning Avatar asked Sep 21 '15 13:09

AlwaysLearning


1 Answers

Creating an object can have side effects.

Unless the compiler can prove that no side effects happen, or there is no part of the standard that mandates that a side effect happens, eliminating this creation of an object is not allowed under either the as-if (the compiler can do anything with your code, so long as it behaves as-if they didn't do the change, up to the requirements of the standard) or elision (you merge lifetime of some objects in some cases, even if it doesn't behave as-if you did not merge them) rules.

As an example, suppose Widgets registered their existence with a central location. When the object was created, the count of Widgets in existence would go up by 1 -- making that not happen is illegal under the standard.

Even if there are no side effects, proving there are no side effects requires the compiler gather up all of the code involved in creating the Widget, and analyzing it for "doing nothing in the end". This can vary from hard (link-time optimization of a large amount of code with peculiar "the object will go away at time Y" constraints to determine if any side effects are mandated), to impossible (we are talking about analyzing the non-trivial properties of a Turing complete computation result).

And all of this for a relatively strange corner case, where "someone created an object for no good reason, then discarded it without using it".

like image 173
Yakk - Adam Nevraumont Avatar answered Oct 23 '22 11:10

Yakk - Adam Nevraumont