CERT C++: DCL53-CPP

Не записывайте синтаксически неоднозначные объявления

Описание

Определение правила

Не записывайте синтаксически неоднозначные объявления.[1]

Реализация Polyspace

Эта проверка проверяет синтаксис неоднозначной декларации.

Примеры

расширить все

Проблема

Этот дефект возникает, когда из объявления не ясно, предназначено ли объявление объекта или функции/параметра. Неоднозначность часто упоминается как самый раздражающий анализ.

Для образца эти заявления неоднозначны:

  • ResourceType aResource();

    Не сразу понятно, aResource ли - функция, возвращающая переменную типа ResourceType или объект типа ResourceType.

  • TimeKeeper aTimeKeeper(Timer());

    Не сразу понятно, aTimeKeeper ли - объект, созданный с неназванным объектом типа Timer или функцию с типом указателя на неназванную функцию в качестве параметра. Указатель на функцию ссылается на функцию без аргументов и возвращаемого типа Timer.

Проверка не помечает неоднозначные объявления с глобальными возможностями. Например, анализ не помечает объявления с глобальными возможностями, используя формат Type a() где Type является типом класса с конструктором по умолчанию. Анализ интерпретирует a как функция, возвращающая тип Type.

Риск

В случае неоднозначного объявления, Стандарт C++ выбирает конкретную интерпретацию синтаксиса. Для образца:

  • ResourceType aResource();
    интерпретируется как объявление функции aResource.

  • TimeKeeper aTimeKeeper(Timer());
    интерпретируется как объявление функции aTimeKeeper с неназванным параметром типа указателя на функцию.

Если вы или другой разработчик или рецензент кода ожидаете другой интерпретации, результаты могут оказаться неожиданными.

Например, позже вы можете столкнуться с ошибкой компиляции, которую трудно понять. Поскольку интерпретация по умолчанию указывает на объявление функции, если вы используете функцию в качестве объекта, компиляторы могут сообщить об ошибке компиляции. Ошибка компиляции указывает, что попытка преобразования функции в объект выполняется без подходящего конструктора.

Зафиксировать

Сделайте заявление однозначным. Например, исправьте эти неоднозначные объявления следующим образом:

  • ResourceType aResource();

    Объявление объекта:

    Если объявление относится к объекту, инициализированному конструктором по умолчанию, перепишите его как:

    ResourceType aResource;
    до C++ 11, или как:
    ResourceType aResource{};
    после C++ 11.

    Объявление функции:

    Если объявление ссылается на функцию, используйте typedef для функции.

    typedef ResourceType(*resourceFunctionType)();
    resourceFunctionType aResource;

  • TimeKeeper aTimeKeeper(Timer());

    Объявление объекта:

    Если объявление ссылается на объект aTimeKeeper инициализированный неназванным объектом класса Timer, добавьте дополнительную пару круглых скобок:

    TimeKeeper aTimeKeeper( (Timer()) );
    до C++ 11, или использовать скобки:
    TimeKeeper aTimeKeeper{Timer{}};
    после C++ 11.

    Объявление функции:

    Если объявление ссылается на функцию aTimeKeeper с неназванным параметром типа указателя на функцию используйте вместо этого именованный параметр.

    typedef Timer(*timerType)();
    TimeKeeper aTimeKeeper(timerType aTimer);

Пример - Объявление функции или объекта
class ResourceType {
      int aMember;
    public:
      int getMember();
};

void getResource() {
    ResourceType aResource();
}

В этом примере aResource может использоваться как объект, но синтаксис объявления указывает на объявление функции.

Коррекция - Используйте {} для объявления объектов

Одной из возможных коррекций (после C++ 11) является использование скобок для объявления объекта.

class ResourceType {
      int aMember;
    public:
      int getMember();
};

void getResource() {
    ResourceType aResource{};
}
Пример - Безымянный объект или Безымянное Объявление Параметр
class MemberType {};

class ResourceType {
      MemberType aMember;
    public:
      ResourceType(MemberType m) {aMember = m;}
      int getMember();
};

void getResource() {
    ResourceType aResource(MemberType()); 
}

В этом примере aResource может использоваться как объект, инициализированный неназванным объектом типа MemberType но синтаксис объявления указывает на функцию с неназванным параметром типа указателя на функцию. Указатель на функцию указывает на функцию без аргументов и типа MemberType.

Коррекция - Используйте {} для объявления объектов

Одной из возможных коррекций (после C++ 11) является использование скобок для объявления объекта.

class MemberType {};

class ResourceType {
      MemberType aMember;
    public:
      ResourceType(MemberType m) {aMember = m;}
      int getMember();
};

void getResource() {
    ResourceType aResource{MemberType()};
}
Пример - Объявление безымянного объекта или именованного параметра функции
class Integer {
       int aMember;
    public:
       Integer(int d) {aMember = d;}
       int getMember();
};

int aInt = 0;
Integer aInteger(Integer(aInt));

В этом примере aInteger возможно, это объект, созданный с неназванным объектом Integer(aInt) (объект класса Integer который сам по себе построен с использованием переменной aInt). Однако синтаксис объявления указывает, что aInteger является функцией с именем параметра aInt типа Integer (лишняя круглая скобка игнорируется).

Коррекция - Использование {} для объявления объектов

Одной из возможных коррекций (после C++ 11) является использование {} для объявления объекта.

class Integer {
       int aMember;
    public:
       Integer(int d) {aMember = d;}
       int getMember();
};

int aInt = 0;
Integer aInteger{Integer{aInt}};
Коррекция - Удалите лишние круглые скобки для объявления именованного параметра

Если aInteger является функцией с именем параметра aInt, удалите лишнее () вокруг aInt.

class Integer {
       int aMember;
    public:
       Integer(int d) {aMember = d;}
       int getMember();
};

Integer aInteger(Integer aInt);

Проверяйте информацию

Группа: 01. Объявления и инициализация (DCL)
Введенный в R2019a

[1] Это программное обеспечение было создано MathWorks, включающее фрагменты: «Сайт SEI CERT-C», © 2017 Университет Карнеги Меллон, Веб-сайт SEI CERT-C + + © 2017 Университет Карнеги Меллон, "Стандарт кодирования SEI CERT C - Правила разработки безопасных, Надежные и безопасные системы - 2016 Edition ", © 2016 Университет Карнеги Меллон, и "Стандарт кодирования SEI CERT C++ - Правила разработки безопасных, Надежные и безопасные системы в C++ - 2016 Edition "© 2016 Университет Карнеги Меллон, с специального разрешения от его Института программной инженерии.

ЛЮБОЙ МАТЕРИАЛ УНИВЕРСИТЕТА КАРНЕГИ МЕЛЛОН И/ИЛИ ЕГО ИНЖЕНЕРНОГО ИНСТИТУТА ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ, СОДЕРЖАЩИЙСЯ В НАСТОЯЩЕМ ДОКУМЕНТЕ, ПОСТАВЛЯЕТСЯ НА БАЗИСЕ «КАК ЕСТЬ». УНИВЕРСИТЕТ КАРНЕГИ МЕЛЛОН НЕ ДАЕТ НИКАКИХ ГАРАНТИЙ, ВЫРАЖЕННЫХ ИЛИ ПОДРАЗУМЕВАЕМЫХ, В ОТНОШЕНИИ ЛЮБОГО ВОПРОСА, ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИВАЯСЬ, ГАРАНТИЮ ПРИГОДНОСТИ ДЛЯ ЦЕЛЕЙ ИЛИ КОММЕРЧЕСКОЙ ВЫГОДЫ, ИСКЛЮЧИТЕЛЬНОСТИ, ИЛИ УНИВЕРСИТЕТ КАРНЕГИ МЕЛЛОН НЕ ДАЕТ НИКАКИХ ГАРАНТИЙ В ОТНОШЕНИИ СВОБОДЫ ОТ ПАТЕНТА, ТОВАРНОГО ЗНАКА ИЛИ НАРУШЕНИЯ АВТОРСКИХ ПРАВ.

Это программное обеспечение и связанная с ним документация не были рассмотрены и не одобрены Университетом Карнеги-Меллон или его Институтом программной инженерии.