C ++中是否有办法声明函数没有副作用?考虑一下:
LOG("message").SetCategory(GetCategory());
现在假设发布版本中的LOG宏创建了一个NullLogEntry对象,该对象将SetCategory()定义为空函数。所以基本上整个表达式可以(并且应该)被优化掉 - 从理论上说,GetCategory()调用可能有一些副作用,所以我想编译器不允许抛弃它。
另一个示例可能是忽略其某些(或全部)参数的函数模板特化,但由于可能的副作用,编译器不允许在调用站点保存此类参数的评估。
我是对的吗?或者编译器能否最终优化此类调用?如果没有,有没有办法提示编译器这个函数没有副作用,所以如果忽略返回值那么可以跳过整个调用?
答案 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中的整个语句,你不必再担心这个了。