Замечания о производительности
Грамотно компилируйте шаблоны
«Замечания о производительности» — бесплатный урок C++ Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения C++ Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс C++ Academy содержит 4 уроков всего.
Компиляция требует затрат
Создание std::regex из строки компилирует шаблон, а это требует значительных затрат. Наибольший выигрыш даёт однократная компиляция с последующим повторным использованием.
- Не создавайте регулярное выражение внутри циклов.
- Компилируйте его при запуске или при первом использовании.
#include <iostream>
#include <regex>
int main() {
std::regex p("\\d+");
std::string inputs[] = {"12", "ab", "99"};
for (const auto& s : inputs) {
std::cout << s << ": " << std::regex_match(s, p) << '\n';
}
return 0;
}Повторное использование скомпилированного шаблона
Создайте шаблон один раз вне цикла и используйте его повторно для каждого входного значения. Построение шаблона на каждой итерации тратит время впустую.
#include <iostream>
#include <regex>
#include <vector>
int main() {
static const std::regex p("[a-z]+");
std::vector<std::string> words = {"hello", "WORLD", "cpp"};
int matches = 0;
for (const auto& w : words) {
if (std::regex_match(w, p)) ++matches;
}
std::cout << "Matched: " << matches << '\n';
return 0;
}static const для констант
Если шаблон никогда не меняется, объявите его как static const внутри функции, чтобы он компилировался ровно один раз для всех вызовов.
#include <iostream>
#include <regex>
bool isEmail(const std::string& s) {
static const std::regex p("\\w+@\\w+\\.\\w+");
return std::regex_match(s, p);
}
int main() {
std::cout << std::boolalpha;
std::cout << isEmail("a@b.com") << '\n';
std::cout << isEmail("nope") << '\n';
return 0;
}Выбор подходящей грамматики
Вариант грамматики регулярных выражений влияет на скорость и доступные возможности. std::regex::ECMAScript используется по умолчанию и является самым функциональным; std::regex::basic или extended проще и иногда работают быстрее.
#include <iostream>
#include <regex>
int main() {
std::regex p("a+", std::regex::extended);
std::cout << std::boolalpha << std::regex_match("aaa", p) << '\n';
return 0;
}Флаг optimize
Добавление std::regex::optimize сообщает механизму регулярных выражений, что следует потратить больше времени на построение шаблона ради более быстрого сопоставления. Это окупается, если сопоставление выполняется много раз.
#include <iostream>
#include <regex>
int main() {
std::regex p("\\d{3}-\\d{4}", std::regex::optimize);
std::cout << std::boolalpha << std::regex_match("123-4567", p) << '\n';
return 0;
}Избегайте катастрофического возврата
Вложенные квантификаторы, такие как (a+)+, на некоторых входных данных могут привести к экспоненциальному увеличению времени работы. Предпочитайте более простые и однозначные шаблоны.
#include <iostream>
#include <regex>
int main() {
std::regex good("a+b");
std::cout << std::boolalpha << std::regex_match("aaaab", good) << '\n';
return 0;
}Используйте якоря, когда это возможно
Якоря ^ и $ позволяют механизму быстро завершить поиск с ошибкой, вместо того чтобы проверять каждую начальную позицию.
#include <iostream>
#include <regex>
int main() {
std::regex p("^[a-z]{3}$");
std::cout << std::boolalpha;
std::cout << std::regex_search("abc", p) << '\n';
std::cout << std::regex_search("abcd", p) << '\n';
return 0;
}По возможности выбирайте простые средства
Если Вам нужно лишь проверить фиксированную подстроку, std::string::find работает значительно быстрее регулярного выражения. Используйте регулярные выражения только для настоящего сопоставления с шаблоном.
#include <iostream>
#include <string>
int main() {
std::string s = "hello world";
bool has = s.find("world") != std::string::npos;
std::cout << std::boolalpha << has << '\n';
return 0;
}Повторное использование объекта соответствия
При многократном поиске используйте один объект std::smatch повторно, вместо того чтобы каждый раз создавать новый, чтобы сократить накладные расходы.
#include <iostream>
#include <regex>
#include <vector>
int main() {
static const std::regex p("(\\d+)");
std::smatch m;
std::vector<std::string> data = {"x1", "y22", "z333"};
for (const auto& s : data) {
if (std::regex_search(s, m, p)) std::cout << m[1] << ' ';
}
std::cout << '\n';
return 0;
}Сузьте шаблон
Конкретные классы символов работают быстрее и безопаснее, чем универсальная точка. Выбирайте [0-9] вместо ., когда нужны цифры.
#include <iostream>
#include <regex>
int main() {
std::regex specific("[0-9]{2}");
std::cout << std::boolalpha;
std::cout << std::regex_match("42", specific) << '\n';
std::cout << std::regex_match("ab", specific) << '\n';
return 0;
}Измеряйте перед оптимизацией
Объедините полученные знания о <chrono>: измеряйте время работы регулярного выражения, чтобы убедиться, что изменение действительно помогает, прежде чем принимать его.
#include <iostream>
#include <regex>
#include <chrono>
int main() {
using namespace std::chrono;
static const std::regex p("\\d+");
auto s = steady_clock::now();
int hits = 0;
for (int i = 0; i < 1000; ++i) {
if (std::regex_search(std::string("x") + std::to_string(i), p)) ++hits;
}
auto e = steady_clock::now();
std::cout << "hits=" << hits << ", timed: " << ((e - s).count() >= 0) << '\n';
return 0;
}Быстрая проверка
Проверьте своё понимание производительности регулярных выражений.
Повторение
Вы научились эффективно использовать регулярные выражения:
- компилировать шаблоны один раз, в идеале как
static const, и повторно использовать их - выбирать подходящую грамматику и рассматривать возможность использования
optimize - избегать катастрофического возврата и по возможности использовать якоря
- использовать более простые инструменты, например
find, для фиксированных подстрок и измерять изменения
На этом курс «Регулярные выражения» завершен.
Часто задаваемые вопросы
Урок «Замечания о производительности» бесплатный?
Да — полный текст урока «Замечания о производительности» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс C++ Academy, подпишись на CoddyKit PRO. Курс C++ Academy содержит 4 уроков всего.
Чему я научусь в уроке «Замечания о производительности»?
Грамотно компилируйте шаблоны Ты практикуешь C++ Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать C++ Academy?
Предыдущий опыт не требуется. C++ Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.
Сколько времени занимает урок «Замечания о производительности»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке C++ Academy?
Да. Каждый урок C++ Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Основы regex
- Группы захвата
- Поиск и замена
- Замечания о производительности