C ++:优化功能,无副作用

时间:2011-07-08 11:40:39

标签: c++ optimization

C ++中是否有办法声明函数没有副作用?考虑一下:

LOG("message").SetCategory(GetCategory()); 

现在假设发布版本中的LOG宏创建了一个NullLogEntry对象,该对象将SetCategory()定义为空函数。所以基本上整个表达式可以(并且应该)被优化掉 - 从理论上说,GetCategory()调用可能有一些副作用,所以我想编译器不允许抛弃它。

另一个示例可能是忽略其某些(或全部)参数的函数模板特化,但由于可能的副作用,编译器不允许在调用站点保存此类参数的评估。

我是对的吗?或者编译器能否最终优化此类调用?如果没有,有没有办法提示编译器这个函数没有副作用,所以如果忽略返回值那么可以跳过整个调用?

3 个答案:

答案 0 :(得分:17)

没有标准的方法可以这样做,但是有些编译器有注释可供您使用,例如,在GCC中,您可以在函数中使用__attribute_pure__标记(或者__attribute__((pure)) )告诉编译器该函数是(即没有副作用)。这在标准C库中广泛使用,例如:

char * str = get_some_string();
for ( int i = 0; i < strlen( str ); ++i ) {
    str[i] = toupper(str[i]);
}

可以由编译器优化为:

char * str = get_some_string();
int __length = strlen( str );
for ( int i = 0; i < __length; ++ i ) {
   str[i] = toupper(str[i]);
}

该函数在string.h标头中声明为:

extern size_t strlen (__const char *__s)
     __THROW __attribute_pure__ __nonnull ((1));

其中__THROW是一个无抛出异常,如果它是一个解析该函数​​的C ++编译器,__nonnull((1))告诉编译器第一个参数不应为null(即如果是参数为null并使用-Wnonnull标志。)

答案 1 :(得分:4)

编译器无法优化对opaque函数的调用。但是,如果GetCategory是内联的,并且因此在调用站点上可见,则允许编译器 ,并且在大多数情况下,如果它看到它不会优化它有副作用,但没有强制要求这样做。

要100%确定地实现您想要的目标,您需要将整个语句包装在一个宏中,该宏将评估为您的发布配置的空语句。

答案 2 :(得分:3)

这是一个熟悉调试模式代码的问题。

唯一可靠的解决方案(用于函数调用)是将所有调试代码包装在宏本身中。

例如,您可以改为使用以下代码:

LOG("message", GetCategory());

然后预处理器会清除Release中的整个语句,你不必再担心这个了。