В мире GNU C / C ++ с компилятором GCC есть Общий атрибут функции «чистый» (который похож на атрибут «const», но с меньшими ограничениями):
Многие функции не имеют эффектов, кроме возвращаемого значения, и их возвращаемое значение зависит только от параметров и / или глобальных переменных. … Некоторыми распространенными примерами чистых функций являются strlen или memcmp. … Атрибут pure налагает аналогичные, но более слабые ограничения на определение функции, чем атрибут const: он позволяет функции читать глобальные переменные. … Поскольку чистая функция не может иметь побочных эффектов, для такой функции не имеет смысла возвращать void.
Разрешено ли чистой функции вызывать любые конструкторы C ++ STL, такие как std::string
или же 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
Задача ещё не решена.
Других решений пока нет …