ПроблемаЭтот дефект возникает, когда из объявления не ясно, предназначено ли объявление объекта или функции/параметра. Неоднозначность часто упоминается как самый раздражающий анализ.
Для образца эти заявления неоднозначны:
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();
Объявление объекта:
Если объявление относится к объекту, инициализированному конструктором по умолчанию, перепишите его как:
до 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);