Мне не нравилась идея управления программой с помощью макросов, поэтому я переписал ее так:
#include <string>
#include <chrono>
#include <iostream>
template <typename T>
int test(std::string s, T pattern, const std::string & msg, size_t num_repeat)
{
int res = 0;
auto start = std::chrono::steady_clock::now();
for(int i = 0; i < num_repeat; i++)
{
s.find(pattern);
s[0] = '.';
}
auto end = std::chrono::steady_clock::now();
std::chrono::duration<double> elapsed_seconds = end-start;
std::cout << msg << " elapsed time: " << elapsed_seconds.count() << "s\n";
return res;
}
int main(int argc, const char* argv[])
{
const int N = 10'000'000;
int res = 0;
std::string s = (argc == 1) ? "MNBVCXZLKJHGFDSAPOIUYTREWQ" : argv[1];
res += test(s, 'A', s + ".find(char): ", N);
res += test(s, "A", s + ".find(string): ", N);
return res & 1;
}
Основная идея заключалась в том, чтобы обмануть компилятор настолько, чтобы он отказался от любой идеи оптимизации. out (это цель s[1] = '.'
и чтения s
из командной строки). Я хотел избежать ситуации, когда компилятор знает и искомую строку, и шаблон, поскольку это может позволить ему использовать некоторые приемы оптимизации, которые мы не хотим использовать в учетной записи int.
Я скомпилировал его, используя g cc 10.1.0 и clang 10.0.0, с -O3
в качестве единственной опции командной строки. (g ++ был запущен с -std=c++17
, у меня это псевдоним).
Результаты зависят от компилятора (что уже можно увидеть в тесте, указанном в вопросе!)
Хорошо. маленькие строки, g ++:
pA1.find(char): elapsed time: 0.124409s
pA1.find(string): elapsed time: 0.125372s
clang:
pA1.find(char): elapsed time: 0.122489s
pA1.find(string): elapsed time: 0.126854s
Разницу трудно измерить. clang систематически дает большее время для строк, но обычно это 3-й значащий di git, вряд ли стоит упоминать.
Теперь строки среднего размера, g ++:
00000000000000000000000000000000000000000000000pA1.find(char): elapsed time: 0.139219s
00000000000000000000000000000000000000000000000pA1.find(string): elapsed time: 0.137838s
clang:
00000000000000000000000000000000000000000000000pA1.find(char): elapsed time: 0.13962s
00000000000000000000000000000000000000000000000pA1.find(string): elapsed time: 0.153506s
Результат для clang систематически в пользу метода «char»; Что касается g ++, победитель колеблется.
Теперь даже большие строки, g ++:
111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000pA1.find(char): elapsed time: 0.170651s
111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000pA1.find(string): elapsed time: 0.177381s
clang:
111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000pA1.find(char): elapsed time: 0.172215s
111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000pA1.find(string): elapsed time: 0.206911s
Для g ++ разницу вряд ли можно заметить, она находится в ожидаемом диапазоне случайных колебаний. Для clang разница ясна и систематична c.
Я повторил это со строкой, состоящей примерно из 1000 символов. Для g ++ разницы нет, для clang около 10%.
Итак, мой вывод - все зависит от компилятора. Для clang разумно следовать совету clang-tidy. Для g ++ этого не должно быть.
Этот ответ не является полным, поскольку было бы интересно узнать различия в реализации std::string::find
между clang и g ++.