2014-02-11 3 views
24

Почему он даже компилируется?Почему я могу назначить 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

Он компилируется в VS2010. – herohuyongtao

+2

@herohuyongtao Вопрос в том, почему. Ответ - это неявные преобразования. – juanchopanza

+1

@HenkHolterman 'new' возвращает указатель. –

ответ

29

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

new UE(true) возвращает указатель. Все указатели могут быть неявно преобразованы в bool, что приводит к true, если они не равны нулю. UE может быть неявно построена из bool. Таким образом, указатель, возвращаемый new, преобразуется в bool, который преобразуется в UE с использованием вашего конструктора, а затем вызывается оператор назначения копирования UE. Разумеется, утечка памяти, выделенная new.

Сообщение о возврате: всегда отмечайте конструкторы с одним аргументом как explicit, если вы на самом деле не хотите, чтобы они были пригодны для неявных преобразований. Под «конструктором с одним аргументом» я имею в виду тот, который можно вызвать с помощью одного аргумента. Либо потому, что у него есть один параметр, либо он имеет больше и все параметры после первых аргументов по умолчанию.

+2

Спасибо, это все объясняет. – BetterWang

+0

Я действительно хочу, чтобы gcc генерировал предупреждение для этого. Похоже, что его следует отличать от «вещей, которые вы, возможно, захотите сделать». Cppcheck (1.63.1) не поймал его. g ++ 4.7.2 не поймал его. –

+0

@ColinDBennett Вы имеете в виду из-за 'нового'? Современный код C++ shoudln't содержит много «новых» вызовов в любом случае, поэтому он будет применяться довольно редко. И любым другим способом получить указатель, такое преобразование является честной игрой, и я был бы очень раздражен, если бы я намеревался его и получил предупреждение. – Angew

8

Существует неявное преобразование с любого указателя на bool. Следовательно, этот код неявно вызывает конструктор одиночных аргументов после преобразования указателя в значение bool

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

struct UE{ 
    explicit UE(bool a = true) { }; 
}; 

Это позволит предотвратить код от компиляции, если конструктор явно не вызывается

1

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

В этом заявлении

ue = new UE(true); 

неявно определяется оператор присваивания копии компилятора называется. Поскольку выражение new UE (true) не равно нулю, оно может быть неявно преобразовано в логическое значение true. Класс UE имеет конструктору конверсии

UE(bool a = true); 

, который преобразует объект типа BOOL к объекту типа UE.

Для предотвращения такого использования вы должны определить конструктор, как явный

explicit UE(bool a = true); 
1

Если вы отмечаете вы конструктору явно это не будет работать:

explicit UE(bool a = true) { }; 

это потому, что существует неявное преобразование из указатель на bool, мы можем видеть, что это разрешено из черновика стандартного раздела C++ 4.12Булевы преобразования говорит (акцент мой):

prvalue арифметики, незаданного перечисления, указателя или указатель типа элемента может быть преобразован в prvalue типа BOOL.

Смежные вопросы