Zero functor design and overhead even with new and removable?
If I have a stateless functor class, but I create it from the heap with a new one, are typical compilers smart enough to fully optimize the scope of creation?
This question arose from the creation of a group of stateless functionaries. If they are allocated on the stack, does their 0 state class body make the stack really not change at all? It looks like this should happen if you later grab the address of the functor instance. Ditto for heap allocation.
In this case, functors always add (trivial but non-zero) overhead when they are created. But perhaps compilers can see if an address is being used and if it cannot eliminate that stack allocation. (Or can it even remove the heap allocation ?)
But what about a functor created as temporary?
#include <iostream>
struct GTfunctor
{
inline bool operator()(int a, int b) {return a>b; }
};
int main()
{
GTfunctor* f= new GTfunctor;
GTfunctor g;
std::cout<< (*f)(2,1) << std::endl;
std::cout<< g(2,1) << std::endl;
std::cout<< GTfunctor()(2,1) << std::endl;
delete f;
}
So, in the concrete example above, the three lines each call the same functor in three different ways. In this example, is there any difference in efficiency between the ways? Or is the compiler able to optimize each line to the point that it is a seamless print operation?
Edit: Most of the answers say that the compiler can never inline / exclude a heap allocated function. But is it really so? Most compilers (GCC, MS, Intel) also optimize communication, which can actually do this optimization. (but does it?)
a source to share
are typical compilers smart enough to fully optimize the build overhead?
When you create them on the heap, I doubt if the compiler is allowed. IMO:
- Calling new implies the use of the new operator.
- operator new is a non-trivial function defined in the runtime library.
- The compiler is not allowed to decide that you really didn't want to call such a function and decide that as an optimization it will silently call it.
When you create them on the stack and don't take their address, then maybe ... or maybe not: I assume that each object is of non-zero size in order to take up some memory to have an identity even if the object does not have states other than his identity.
a source to share
Obviously it depends on your compiler.
I would say
-
No compiler will optimize an object on the heap. (This is because, as ChrisW says, compilers will never optimize a call to a new one, which is almost certainly defined in a different translation unit.)
-
Some compilers optimize the named object on the stack. I know gcc to do this optimization quite often.
-
Most compilers optimize an unnamed object on the stack. This is one of the "standard" optimizations in C ++, especially when more advanced C ++ users tend to create a lot of unnamed temporary variables.
Unfortunately, these are only rules of thumb. Optimizers are notoriously unpredictable; really the only way to know what your compiler is doing is to read the assembly output.
a source to share
A C ++ object is always nonzero. "Empty base class optimization" allows an empty base class to be of zero size, but this does not apply here.
I have not worked on a C ++ optimizer, so everything I say is just speculation. I think the 2nd and 3rd will be expanded in strict accordance and there will be no overhead and no GTFunctor will be created. However, a pointer functor is a completely different story. In your example, this may seem simple enough and any optimizer should be able to eliminate heap allocation, but in a non-trivial program, you can create functors in one translation unit and use it in another. Or even in another library where the compiler / linker / loader / runtime system has no source code and is nearly impossible to optimize. Given the fact that it is not easy to optimize, the potential performance gain is small, and the number of cases where an empty functor is allocated on the heap is probably small, I thinkthat most SEO programmers probably won't put this optimization on their to-do list.
a source to share
Simple way to answer the heap question:
GTfunctor *f = new GTfunctor;
The value f
shouldn't be null, so what should it be? And you also had:
GTfunctor *g = new GTfunctor;
Now the value g
shouldn't equal the value f
, so what should it be?
Also, neither f
nor g
can be equal to any other pointer derived from new
, unless any pointer elsewhere is in any way initialized to be equal f
or g
, which (depending on the code that comes after) may involve learning that , which does the rest of the program.
Yes, if by looking at the code locally the compiler can see that you never rely on any of these requirements, then it can rewrite in such a way that no heap allocation occurs. The problem is, if your code was that simple, you could probably do it rewrite yourself and end up with a more readable program, for example. your test program will look like a g
stack based example . Thus, real programs will not benefit from such compiler optimization.
Presumably the reason you do this is because sometimes the functor has data, depending on which type is chosen at runtime. Thus, compile time analysis cannot use its magic here.
a source to share
The C ++ standard states that every object (imho on the heap) must be at least one byte in size, so it can be uniquely addressed.
Generating functors with new ones can lead to two problems:
- The constructs cannot be optimized at all. New is a function with complex side effects (bad_alloc).
- Since you are accessing the functor indirectly, the compiler may not be able to inline the function.
Chances are you won't see the functor feature if you generate it on the stack.
Side note: no inline operator needed. Every function defined in a class definition is considered inlineable.
a source to share
The compiler can probably figure out that operator () doesn't use any member variables and optimizes it to max. However, I would not make any assumptions about local or heap variables.
Edit: When in doubt, enable the build build option in your compiler and see what it actually does. There is no point in listening to a bunch of idiots on the internet when you can see the real answer for yourself.
a source to share
The answer to your question has two aspects.
-
The compiler will optimize the heap allocation: I strongly doubt it, but I'm not a standard guy, so I have to look for him.
-
Is it possible to optimize the compiler with the built-in object operator ()? Yes. Until you specify the call as virtual, even the pointer dereference is not actually performed.
a source to share