
Что интересно, сам Уорд Каннингем авторство этого закона отвергает.
Size: a a a
x86-64 clang (experimental -Wlifetime)
. Как же этот анализатор работает на практике?<string_view>
. Аналогом этого типа в Rust выступает &str
.#include <string>
#include <string_view>
using sv = std::string_view;
sv shortest(sv a, sv b) {
return a.size() < b.size() ? a : b;
}
sv cut_prefix(sv prefix, sv str) {
//
не спрашивайте if (str.rfind(prefix, 0) == 0) {
return str.substr(prefix.size());
} else {
return str;
}
}
Эти функции имеют одинаковые сигнатуры, но между ними есть большое отличие: shortest может вернуть любой из двух аргументов, а вот cut_prefix может вернуть только второй аргумент или подстроку из него.-Wlifetime
на практике:sv example_should_err(int n, sv str) {На первый пример компилятор выдаёт предупреждение:
auto n_str = std::to_string(n);
return shortest(n_str, str);
}
sv example_should_ok(int n, sv str) {
auto n_str = std::to_string(n);
return cut_prefix(n_str, str);
}
<source>:20:5: warning: returning a dangling pointer [-Wlifetime]И совершенно правильно, потому что тут может быть возвращён string_view, созданный из временной строки, которая уничтожается на выходе из функции. Что же касается второго примера... Тоже предупреждение. Причём то же самое :/ Хотя тут string_view от n_str заведомо не покидает пределы функции.
return shortest(n_str, str);
^~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:20:5: note: pointee 'n_str' left the scope here
return shortest(n_str, str);
^~~~~~~~~~~~~~~~~~~~~~~~~~~
-Wlifetime-filter
. Цитирую: "Reduce the number of false-postives at the cost of additional false negatives.". Добавляем этот флаг и... Получаем тот же самый выхлоп.template <typename F> sv example_hof(int n, sv str, F func) {Кладём в компилятор и... Получаем ноль предупреждений.
auto n_str = std::to_string(n);
return func(n_str, str);
}
sv example_hof_should_ok(int n, sv str) {
return example_hof(n, str, cut_prefix);
}
sv example_hof_should_err(int n, sv str) {
return example_hof(n, str, shortest);
}
sv example_hof(int n, sv str, sv (*func)(sv, sv)) {Проверяем... Ноль предупреждений.
auto n_str = std::to_string(n);
return func(n_str, str);
}
// example_hof_should_ok и example_hof_should_err остались без изменений
typed_phy
и случайно наткнулся на такое прекрасное...++
и --
). Как и любые операторы, их можно перегружать для своих типов. Но есть один нюанс: как различать префиксный и постфиксный инкременты? В C++ решение таково: префиксный оператор не принимает аргументов, а постфиксный принимает неиспользуемый параметр типа int.