exponenta event banner

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 Университет Карнеги-Меллон, со специальным разрешением от его Института программного обеспечения.

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

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