在带有 GCC 编译器的 C/C++ 的 gnu 世界中,有通用函数属性“纯”(类似于“const”属性,但限制较少):
许多函数除了返回值外没有任何影响,它们的返回值仅取决于参数和/或全局变量。...纯函数的一些常见示例是 strlen 或 memcmp。... pure 属性对函数的定义施加了与 const 属性类似但更宽松的限制:它允许函数读取全局变量。...因为纯函数不能有任何副作用,所以这样的函数返回 void 是没有意义的。
是否允许纯函数调用任何 C++ STL 构造函数,例如std::string
or std::vector
?例如,此代码是否合法,为什么不合法?(这是否合法__attribute__((const))
?)
#include <string>
#include <cstdio>
__attribute__((pure)) std::string GetFilesystemSeparator(int unixvar) {
if(unixvar) {
return "/";
} else {
return "\\";
}
}
int main() {
std::string dirname1="dir1";
std::string dirname2="dir2";
std::string filename="file";
int unixvar;
std::string path;
puts("Unix style:");
unixvar = 1;
path=dirname1 + GetFilesystemSeparator(unixvar) + dirname2 + GetFilesystemSeparator(unixvar) + filename;
puts(path.c_str());
puts("Not Unix style:");
unixvar = 0;
path=dirname1 + GetFilesystemSeparator(unixvar) + dirname2 + GetFilesystemSeparator(unixvar) + filename;
puts(path.c_str());
return 0;
}
g++ pure.cc -o pure -fverbose-asm --save-temps
clang++ pure.cc -o pure1 -O3 -save-temps
有一些对复杂 std::sting 构造函数的调用,它可能分配内存并写入一些用于管理空闲和分配内存的全局变量:
less pure.s
...
_Z22GetFilesystemSeparatorB5cxx11i:
call _ZNSaIcEC1Ev@PLT #
call _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC1EPKcRKS3_@PLT #
例如,在将"/"
和"\\"
常量的长度更改为 100 个字符后,我从构造函数中调用了new
和调用:malloc(101)
ltrace -e '*@*' ./pure3
...
libstdc++.so.6->strlen("////////////////////////////////"...) = 100
libstdc++.so.6->_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE12_M_constructIPKcEEvT_S8_St20forward_iterator_tag(0x7ffc7b66a840, 0x558899f74570, 0x558899f745d4, 0 <unfinished ...>
libstdc++.so.6->_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE9_M_createERmm(0x7ffc7b66a840, 0x7ffc7b66a6b0, 0, 0 <unfinished ...>
libstdc++.so.6->_Znwm(101, 0x7ffc7b66a6b0, 0, 0 <unfinished ...>
libstdc++.so.6->malloc(101) = 0x55889bef0c20
<... _Znwm resumed> ) = 0x55889bef0c20
<... _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE9_M_createERmm resumed> ) = 0x55889bef0c20
libstdc++.so.6->memcpy(0x55889bef0c20, "////////////////////////////////"..., 100) = 0x55889bef0c20