# V1068. Do not define an unnamed namespace in a header file.

Анализатор обнаружил анонимное пространство имен, объявленное в заголовочном файле. Такой заголовочный файл создаёт копии символов с "внутренним связыванием" (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;
      }
    }

Данная диагностика классифицируется как:

CERT-DCL59-CPP

Взгляните на примеры ошибок, обнаруженных с помощью диагностики V1068.