V1061. Extending 'std' or 'posix' namespace may result in undefined behavior.

Анализатор обнаружил расширение пространства имён 'std' или 'posix'. Несмотря на то, что такая программа успешно компилируется и исполняется, модификация данных пространств имён может привести к неопределённому поведению программы, если иное не указано стандартом.

Содержимое пространства имен 'std' определяется исключительно комитетом стандартизации, и стандарт запрещает добавлять в него:

  • декларации переменных;
  • декларации функций;
  • декларации классов/структур/объединений;
  • декларации перечислений;
  • декларации шаблонов функций, классов и переменных (C++14);

Стандарт разрешает добавлять следующие специализации шаблонов, определенных в пространстве имен 'std', если они зависят хотя бы от одного определенного в программе типа (program-defined type):

  • полная или частичная специализация шаблона класса;
  • полная специализация шаблона функции (до C++20);
  • полная или частичная специализация шаблона переменной, не лежащих в заголовочном файле '<type_traits>' (до C++20);

Однако, специализации шаблонов, лежащих внутри классов или шаблонов классов, запрещены.

Наиболее частым вариантом, когда пользователь расширяет пространство имен 'std', является добавление своей перегрузки функции 'std::swap' и полной/частичной специализации шаблона класса 'std::hash'.

Рассмотрим фрагмент кода с добавлением перегрузки 'std::swap':

template <typename T>
class MyTemplateClass
{
  ....
};

class MyClass
{
  ....
};

namespace std
{
  template <typename T>
  void swap(MyTemplateClass<T> &a, MyTemplateClass<T> &b) noexcept // UB
  {
    ....
  }

  template <>
  void swap(MyClass &a, MyClass &b) noexcept // UB since C++20
  {
    ....
  };
}

Первый шаблон функции не является специализацией 'std::swap', и такая декларация ведет к неопределенному поведению. Второй шаблон функции является специализацией, и до C++20 поведение программы определено. Однако, в данном случае можно поступить иначе: можно вынести обе функции из пространства имен 'std' и поместить их в то пространство имен, где определены классы:

template <typename T>
class MyTemplateClass
{
  ....
};

class MyClass
{
  ....
};

template <typename T>
void swap(MyTemplateClass<T> &a, MyTemplateClass<T> &b) noexcept
{
  ....
}

void swap(MyClass &a, MyClass &b) noexcept
{
  ....
};

Теперь, когда необходимо написать шаблон функции, который применяет функцию swap для двух объектов типа T, можно написать следующий код:

template <typename T>
void MyFunction(T& obj1, T& obj2)
{
  using std::swap; // make std::swap visible for overload resolution
  ....
  swap(obj1, obj2); // best match of 'swap' for objects of type T
  ....
}

Теперь, компилятор выберет нужную перегрузку функции на основе поиска с учетом аргументов (argument-dependent lookup, ADL) – пользовательские функции 'swap' для класса 'MyClass' и для шаблона класса 'MyTemplateClass' и стандартную версию 'std::swap' для остальных типов.

Разберем следующий пример со специализацией шаблона класса 'std::hash':

namespace Foo
{
    class Bar
    {
      ....
    };
}

namespace std
{
  template <>
  struct hash<Foo::Bar>
  {
    size_t operator()(const Foo::Bar &) const noexcept;
  };
}

С точки зрения стандарта этот код является валидным, и анализатор в этой ситуации не выдает предупреждение. Однако, начиная с C++11, можно и в этом случае поступить иначе, написав специализацию шаблона класса за пределами пространства имен 'std':

template <>
struct std::hash<Foo::Bar>
{
  size_t operator()(const Foo::Bar &) const noexcept;
};

В отличие от пространства имен 'std', стандарт C++ запрещает абсолютно любую модификацию пространства имён 'posix':

namespace posix
{
  int x; // UB
}

Дополнительная информация:

  • Стандарт C++17 (working draft N4659), пункт 20.5.4.2.1
  • Стандарт C++20 (working draft N4860), пункт 16.5.4.2.1

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

  • CERT-DCL58-CPP

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


Найденные ошибки

Проверено проектов
411
Собрано ошибок
14 123

А ты совершаешь ошибки в коде?

Проверь с помощью
PVS-Studio

Статический анализ
кода для C, C++, C#
и Java

goto PVS-Studio;
Этот сайт использует куки и другие технологии, чтобы предоставить вам более персонализированный опыт. Продолжая просмотр страниц нашего веб-сайта, вы принимаете условия использования этих файлов. Если вы не хотите, чтобы ваши данные обрабатывались, пожалуйста, покиньте данный сайт. Подробнее →
Принять