Почему я могу назначить struct указателем?
Почему он даже компилируется?
struct UE{
UE(bool a = true) { };
// UE(){}; // if UE took no initial args and called below, gcc will complain.
};
class VA {
protected:
UE ue;
public:
VA();
};
VA::VA()
{
ue = new UE(true); // ???why???
// ue = new UE(); // will complain
}
Я пробовал с gcc (GCC) 4.6.2.
Как я могу назначить структуру с указателем?
Ответы
Ответ 1
Вы сталкиваетесь с тем, что вы не отмечали свой конструктор как explicit
, и поэтому его можно использовать для неявных преобразований.
new UE(true)
возвращает указатель. Все указатели могут быть неявно преобразованы в bool
, что приводит к true
, если они не равны нулю. UE
может быть неявно построено из a bool
. Таким образом, указатель, возвращаемый new
, преобразуется в bool
, который преобразуется в UE
с помощью вашего конструктора, а затем вызывается оператор назначения копирования UE
. Конечно, память, выделенная new
, просочилась.
Сообщение о возврате: всегда отмечайте конструкторы с одним аргументом как explicit
, если вы действительно не хотите, чтобы они использовались для неявных преобразований. Под "конструктором с одним аргументом" я имею в виду тот, который можно вызвать с помощью одного аргумента. Либо потому, что у него есть один параметр, либо у него есть все и все параметры после первых аргументов по умолчанию.
Ответ 2
Существует неявное преобразование с любого указателя на bool
. Следовательно, этот код неявно вызывает конструктор одиночных аргументов после преобразования указателя в значение bool
Один из способов исправить это состоит в том, чтобы сделать однозначный конструктор параметров явным.
struct UE{
explicit UE(bool a = true) { };
};
Это предотвратит компиляцию кода, если явно не будет вызван конструктор
Ответ 3
Любой скалярный тип может быть преобразован в логическое значение true или false в зависимости от того, равно ли оно его нулю или нет.
В этом утверждении
ue = new UE(true);
вызывается неявно определяемый оператором присваивания копии компилятора. Поскольку выражение new UE (true) не равно нулю, оно может быть неявно преобразовано в логическое значение true. Класс UE имеет конструктор преобразования
UE(bool a = true);
который преобразует объект типа bool в объект типа UE.
Чтобы предотвратить такое использование, вы должны определить конструктор как явный
explicit UE(bool a = true);
Ответ 4
Если вы отметите явно конструктор, это не будет работать:
explicit UE( bool a = true) { };
это потому, что есть неявное преобразование из указателя в bool, мы можем видеть, что это разрешено из стандартного раздела проекта С++ 4.12
Логические преобразования говорят (выделено мной):
Значение арифметики, неперечисленное перечисление, указатель или указатель на тип члена может быть преобразован в prvalue типа bool.