WaZoX Ответов: 2

Наличие проблем с" Союзом " вынуждает инициировать всех членов, а не только активного.


Привет!

У меня есть следующий код (с некоторыми ненужными деталями, удаленными):

Заголовок:
enum class TargetType : uint8
{
	NoTarget
	, Location
	, Actor
};


class Target
{
public:

	Target();
	Target(const FVector &inLocation);
	Target(const AActor *inTargetActor);

	// ... some methods here

private:

	TargetType targetType;

	union
	{
		FVector location;
		TWeakObjectPtr<AActor> targetActor;
	};
};


Источник:
// ... header includes

Target::Target()
	: targetType { TargetType::NoTarget }
{
}

Target::Target(const FVector &inLocation)
	: targetType { TargetType::Location }
	, location(inLocation)
{
}

Target::Target(const AActor *inTargetActor)
	: targetType { TargetType::Actor }
	, targetActor(inTargetActor)
{
}

// ... some code


Когда я пытаюсь скомпилировать это, я получаю следующие ошибки:
error C4582: 'Target::location': constructor is not implicitly called
error C4582: 'Target::targetActor': constructor is not implicitly called
error C4582: 'Target::targetActor': constructor is not implicitly called
error C4582: 'Target::location': constructor is not implicitly called


Составитель жалуется на то, что члены Союза не инициируются. Первый конструктор жалуется на то, что оба члена не инициируются. Два других жалуются на то, что член не инициируется, поэтому, например, если я хочу использовать местоположение, компилятор хочет, чтобы я также инициировал targetActor.

Мой вопрос заключается в том, действительно ли я должен инициировать оба члена, если я не собираюсь использовать их, например, в первом конструкторе? Для меня это не имеет никакого смысла, так как я не хочу использовать данные в этом случае? Кроме того, почему я должен инициировать
Target::location
когда я хочу использовать
Target::targetActor
как активный член? Я что-то здесь упускаю?

Заранее спасибо!

Что я уже пробовал:

Я уверен, что кто-то лучше меня понимает, что происходит!
Спасибо за любую помощь!

Примечание: Я использую C++11, но существовал только тег C++14?

2 Ответов

Рейтинг:
2

Richard MacCutchan

Вам нужно дать Союзу имя, чтобы получить доступ к его членам внутри класса. Видеть Объединения[^].


WaZoX

Спасибо за ваш ответ! Имя Союза не требуется в ссылке, которую вы разместили, см. Пример "неограниченные союзы". Я смотрел на него раньше, но не могу понять, почему я не могу заставить свой код работать. Для меня этот пример выглядит почти так же, как и мой?

Richard MacCutchan

Может быть, это как-то связано с типами объектов в объединении. Извините, я не могу думать ни о чем другом.

WaZoX

Мне придется исследовать это дальше. Спасибо!

Рейтинг:
18

Jochen Arndt

Какая версия компилятора (я думаю, Microsoft)?
Я протестировал аналогичный код (используя другие типы членов союза) с компилятором GNU и не получил никаких ошибок.

В зависимости от поддержки компилятора C++11 он может быть получен из-за того, что члены объединения не являются типами данных POD:

Объединения не могут содержать нестатический элемент данных с нетривиальной специальной функцией-членом (конструктор копирования, оператор присваивания копирования или деструктор). (до C++11)


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

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

Не более чем один элемент variant может иметь инициализатор элемента по умолчанию. (начиная с C++11)

Таким образом, это может быть решено путем предоставления соответствующих конструкторов (что требует использования не анонимного объединения):
union loc
{
    FVector location;
    TWeakObjectPtr<AActor> targetActor;
    loc() { /* initialise one member here */ }
    loc (const FVector &inLocation) { location = inLocation; }
    loc (const AActor *inTargetActor) { targetActor = inTargetActor; }
};


WaZoX

Спасибо за ваше предложение.

Я изменил Союз на этот:

union TargetData
{
TargetData () { location = FVector(); }
TargetData (const FVector &inLocation) { location = inLocation; }
TargetData (AActor *inActor) { targetActor = inActor; }

Расположение фвектора;
TWeakObjectPtr< aactor & gt; targetActor;
} targetData;

Теперь вместо этого я получаю жалобы на объединение, например, для пустого конструктора я получаю следующие ошибки:
ошибка C4582: 'Target:: TargetData:: location': конструктор не вызывается неявно
ошибка C4582: 'Target:: TargetData:: targetActor': конструктор не вызывается неявно
...

Jochen Arndt

Тогда у меня больше нет идей, кроме проверки того, можно ли игнорировать ошибку (я предполагаю, что изначально это предупреждение, но вы включили обработку предупреждений как ошибок):

#pragma warning (disable: 4582)
// problematic code here (the complete union)
#pragma warning (enable: 4582)

Но при этом вы должны убедиться, что члены были инициализированы перед их использованием.

Я не знаю типов, но предполагаю, что это, по крайней мере, TWeakObjectPtr-шаблон. Если бы хотя бы один член был каким-то сложным, я бы не использовал его внутри союза, чтобы избежать побочных эффектов. Тогда, возможно, было бы лучше использовать структуру, когда дополнительное потребление памяти может быть принято.

Я искал номер ошибки и не нашел его ни на MSDN, ни на странице. Поэтому, возможно, было бы лучше спросить на форуме MSDN VC++, где разработчик компилятора мог бы ответить. В крайнем случае вы также можете обратиться в поддержку МС.

WaZoX

Это сделало свое дело.

Да, это тип шаблона, так что вы, вероятно, правы. Имеет смысл разрешить некоторое дополнительное потребление памяти, чтобы избежать побочных эффектов!

Большое спасибо за вашу помощь!

Jochen Arndt

Спасибо за обратную связь и принятие моего решения.