我正在考虑在我的 C++ 代码中更多地使用纯/常量函数。 (pure/const attribute in GCC)
但是,我很好奇我应该对它有多严格,什么可能会破坏。
最明显的情况是调试输出(以任何形式,可以在 cout、某个文件或某个自定义调试类中)。我可能会有很多功能,尽管有这种调试输出,但它们没有任何副作用。无论是否生成调试输出,这绝对不会影响我的应用程序的其余部分。
或者我正在考虑的另一种情况是使用一些 SmartPointer 类,当处于 Debug模式时,它可能会在全局内存中做一些额外的事情。如果我在纯/常量函数中使用这样的对象,它确实有一些轻微的副作用(从某种意义上说,一些内存可能会有所不同)但不应该有任何真正的副作用(从某种意义上说,行为在任何不同的方式)。
互斥锁和其他东西也是如此。我可以想到许多复杂的情况,其中它有一些副作用(从某种意义上说,一些内存会有所不同,甚至可能创建一些线程,进行一些文件系统操作等)但没有计算差异(所有这些副作用很可能会被排除在外,我什至更愿意这样做)。
所以,总而言之,我想将函数标记为纯/常量,严格意义上来说它们不是纯/常量。一个简单的例子:
int foo(int) __attribute__((const));
int bar(int x) {
int sum = 0;
for(int i = 0; i < 100; ++i)
sum += foo(x);
return sum;
}
int foo_callcounter = 0;
int main() {
cout << "bar 42 = " << bar(42) << endl;
cout << "foo callcounter = " << foo_callcounter << endl;
}
int foo(int x) {
cout << "DEBUG: foo(" << x << ")" << endl;
foo_callcounter++;
return x; // or whatever
}
请注意,函数 foo 不是严格意义上的 const。不过,foo_callcounter 到底是什么并不重要。不做调试语句也没关系(以防不调用函数)。
我希望输出:
DEBUG: foo(42)
bar 42 = 4200
foo callcounter = 1
并且没有优化:
DEBUG: foo(42) (100 times)
bar 42 = 4200
foo callcounter = 100
这两种情况都很好,因为对我的用例来说唯一重要的是 bar(42) 的返回值。
在实践中效果如何? 如果我将这些函数标记为纯/常量,它会破坏什么(考虑到代码都是正确的)?
请注意,我知道某些编译器可能根本不支持此属性。 (顺便说一句,我正在收集它们 here 。)我还知道如何以代码保持可移植性的方式使用这些属性(通过#defines)。此外,我感兴趣的所有编译器都以某种方式支持它;所以我不在乎我的代码在没有编译器的情况下运行速度是否更慢。
我也知道优化后的代码可能会根据编译器甚至编译器版本而有所不同。
非常相关的还有this LWN article "Implications of pure and constant functions" ,尤其是“秘籍”一章。 (感谢 ArtemGr 的提示。)
最佳答案
I'm thinking of using pure/const functions more heavily in my C++ code.
这是一个滑坡。这些属性是非标准的,它们的好处主要限于微优化。
这不是一个好的权衡。相反,请编写干净的代码,不要应用此类微优化,除非您已仔 segmentation 析并且无法绕过它。或者根本没有。
请注意,原则上这些属性非常好,因为它们明确地为编译器和程序员声明了函数的隐含假设。这很好。但是,还有其他方法可以明确类似的假设(包括文档)。但由于这些属性是非标准的,它们在普通代码中没有位置。它们应该被限制在非常在作者试图为每个编译器发出最佳代码的性能关键库中明智地使用。也就是说,作者意识到只有 GCC 可以使用这些属性,并为其他编译器做出了不同的选择。
关于c++ - C++ 中的纯/常量函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2798071/