C++: optimizing function with no side effects
Is there a way in C++ to declare that a function has no side effects? Consider:
LOG("message").SetCategory(GetCategory());
Now suppose that the LOG macro in release builds creates a NullLogEntry object that has SetCategory() defined as an empty function. So basically the whole expression could (and should) be optimized away -- expcept that, in theory, the GetCategory() call may have some side effects, so I guess the compiler is not permitted to just throw it away.
Another example could be a function template specialization that ignores some (or all) of 开发者_Python百科its arguments, yet the compiler is not allowed to save the evaluation of such arguments at the call site due to possible side effects.
Am I right? Or can compilers optimize away such calls anyway? If not, is there a way to hint the compiler that this function has no side effects, so if the return value is ignored then the whole call can be skipped?
There is no standard way of doing so, but some compilers have annotations that you can use to that effect, for example, in GCC you can use the __attribute_pure__
tag in a function (alternatively __attribute__((pure))
) to tell the compiler that the function is pure (i.e. has no side effects). That is used in the standard C library extensively, so that for example:
char * str = get_some_string();
for ( int i = 0; i < strlen( str ); ++i ) {
str[i] = toupper(str[i]);
}
Can be optimized by the compiler into:
char * str = get_some_string();
int __length = strlen( str );
for ( int i = 0; i < __length; ++ i ) {
str[i] = toupper(str[i]);
}
The function is declared in the string.h header as:
extern size_t strlen (__const char *__s)
__THROW __attribute_pure__ __nonnull ((1));
Where __THROW
is a no throw exception in case that it is a C++ compiler parsing the function, and __nonnull((1))
tells the compiler that the first argument should not be null (i.e. trigger a warning if the argument is null and -Wnonnull flag is used).
The compiler cannot optimize away a call to the opaque function. However, if GetCategory
is inline, and, hence visible at the call site, the compiler is allowed to, and it most cases, will optimize it away if it sees that it doesn't have side effects, but is not mandated to do so.
To achieve what you want with 100% certainty you need to wrap the entire statement in a macro that will evaluate to an empty statement for your release configuration.
This is a know issue with having Debug Mode code.
The only reliable solution (for function calls) is to wrap all the debugging code within the macro itself.
For example, you could perhaps use the following code instead:
LOG("message", GetCategory());
Then the preprocessor would wipe out the whole statement in Release, and you would not have to worry about this any longer.
精彩评论