Анализатор обнаружил анонимное пространство имен, объявленное в заголовочном файле. Такой заголовочный файл создаёт копии символов с "внутренним связыванием" (internal linkage) в каждой единице трансляции, включающей этот заголовочный файл. Это приводит к "раздуванию" объектных файлов, что может быть нежелательным поведением.
Рассмотрим простой пример заголовочного файла с анонимным пространством имен:
// utils.hpp #pragma once #include <iostream> namespace { int global_variable; void set_global_variable(int v) { std::cout << global_variable << std::endl; global_variable = v; } }
Каждая единица трансляции при включении заголовочного файла 'utils.hpp' получит свой экземпляр переменной 'global_variable', не связанной с другими экземплярами и не доступной из других единиц трансляции. Также будет сгенерировано несколько избыточных функций 'set_global_variable'. До стандарта C++17 такой код мог встречаться в header-only библиотеках для того, чтобы не нарушать One Definition Rule при включении заголовочных файлов в несколько единиц трансляции. Также подобный код может появиться из-за неаккуратного рефакторинга, например, при переносе анонимного пространства имен из компилируемого файла в заголовочный файл.
Стоит отметить, что данное правило распространяется и на безымянные пространства имен, вложенные в другие пространства имен:
namespace my_namespace { int variable1; // namespace-scope non-const variable // 'variable1' has external linkage namespace // <= { int variable2; // unnamed namespace applies 'static' // 'variable2' has internal linkage } }
Если необходимо создать ровно один экземпляр символа для header-only библиотеки, то можно воспользоваться спецификатором 'inline' (начиная с C++17, действует и для переменных):
// utils.hpp #pragma once #include <iostream> inline int global_variable; // ok since C++17 inline void set_global_variable(int v) { std::cout << global_variable << std::endl; global_variable = v; }
Если используется более ранняя версия стандарта, но библиотека не header-only, то можно объявить символы как 'extern' в заголовочном файле и определить их в одном из юнитов трансляции:
// utils.hpp #pragma once extern int global_variable; void set_global_variable(int v); // functions implicitly // have external linkage ('extern')
// utils.cpp #include "utils.hpp" #include <iostream> int global_variable; void set_global_variable(int v) { std::cout << global_variable << std::endl; global_variable = v; }
В том случае, когда используется более старая версия стандарта, но библиотека должна быть header-only, срабатывание можно подавить комментарием:
// utils.hpp #pragma once #include <iostream> namespace //-V1068 { int global_variable; void set_global_variable(int v) { std::cout << global_variable << std::endl; global_variable = v; } }
Данная диагностика классифицируется как:
|
Взгляните на примеры ошибок, обнаруженных с помощью диагностики V1068. |