Недавно я встретил ошибку в проекте C++, связанную с неназванной защитой области, как в этом вопросе:
LockGuard(mutex);
Посмотрите простую демонстрацию.
Такую ошибку очень сложно обнаружить при просмотре изменений, а также сложно отладить. Я хотел бы использовать автоматическую проверку в CI.
Есть ли какое-либо предупреждение компилятора (gcc, clang, cl) или инструмент статического анализа, который может указать на проблему?
clang-tidy
замечает это.
я удалил твой UPD. Дискуссия в комментариях не была бесполезной. Необходимо было уточнить вопрос. Вот для чего нужны комментарии
В новых версиях стандарта C++ есть атрибут [[nodiscard]]
, который также можно применять к конструкторам.
Итак, если вы напишете класс, подобный следующему:
template<typename M>
class my_lock_guard {
public:
[[nodiscard]] my_lock_guard(M& mutex)
: m_mutex(mutex)
{
m_mutex.lock();
}
~my_lock_guard()
{
m_mutex.unlock();
}
private:
M& m_mutex;
};
тогда следующий код выдаст предупреждение компилятора в достаточно новых компиляторах:
static std::mutex my_mutex_var;
static int global_var;
void foo()
{
my_lock_guard<std::mutex>{my_mutex_var};
global_var = 42;
}
Вы можете проверить это в обозревателе компиляторов, где три основных компилятора выдадут предупреждение об использовании в foo()
. (Но если вы добавите туда имя переменной, предупреждение исчезнет.)
Таким образом, для всех классов RAII этого типа, которые вы пишете самостоятельно (т. е. классов, которые просто существуют для использования в текущей области видимости, но никогда не затрагиваются после создания), просто добавьте [[nodiscard]]
ко всем конструкторам, и это автоматически вызовет соответствующие предупреждения компилятора.
К сожалению, этот атрибут еще не был добавлен в достаточное количество частей стандартной библиотеки C++ в доступных на данный момент версиях стандартов. Ни lock_guard
, ни scoped_lock
, ни unique_lock
, ни shared_lock
не имеют [[nodiscard]]
конструкторов вплоть до C++23 включительно. Для этих классов стандартной библиотеки вам придется использовать другие инструменты. Как упоминалось другими людьми в комментариях, clang-tidy
, очевидно, также может обнаруживать проблемы такого типа, независимо от наличия атрибута. Я бы по-прежнему рекомендовал, чтобы вы в любом случае использовали этот атрибут в соответствующих случаях, потому что тогда вы уже увидите эту проблему на уровне компилятора.
(Также обратите внимание, что my_lock_guard
выше — это минималистичный пример, а не полная замена std::lock_guard
; пожалуйста, не используйте мой пример в рабочем коде.)
Во-первых, это анализируется как
std::lock_guard<std::mutex> mutex;
и вызывает ошибку компиляции, посколькуlock_guard
не является конструируемым по умолчанию. Если я заменю(...)
на{...}
, то Clang на-stdlib=libc++
выдаст предупреждение (потому что конструктор nodiscard), а MSVC также выдаст предупреждение (видимо, есть специальное предупреждение?).