#c #unreal-engine4
Вопрос:
При написании спецификаций UE4 я нахожу, что иногда значение, переданное в лямбду, вызывает сбой или непредсказуемый результат, в то время как в других случаях это не так.
Например, вызов любого метода для Matcher
объекта внутри It()
в приведенном ниже примере приведет к сбою (все значения являются данными мусора, когда я проверяю их в отладчике Rider).:
void FPF2AbilityBoostRuleOptionMatcherSpec::Define()
{
Describe(TEXT("when there are no rule options"), [=, this]()
{
const TArray<FPF2AbilityBoostRuleOption> RuleOptions = {};
Describe(TEXT("CanApplyAbilityBoost()"), [=, this]()
{
FPF2AbilityBoostRuleOptionMatcher Matcher(RuleOptions);
It(TEXT("returns `false` for all abilities"), [=, this, amp;Matcher]()
{
for (const autoamp; AbilityScoreType : TEnumRange<EPF2CharacterAbilityScoreType>())
{
TestFalse(
FString::Format(TEXT("CanApplyAbilityBoost({0})"), { PF2EnumUtils::ToString(AbilityScoreType)}),
Matcher.CanApplyAbilityBoost(AbilityScoreType)
);
}
});
});
// ...
});
// ...
}
Переключение его на передачу по значению приводит к ошибке IDE, но он компилируется и выходит из строя, то же самое было ссылкой:
void FPF2AbilityBoostRuleOptionMatcherSpec::Define()
{
Describe(TEXT("when there are no rule options"), [=, this]()
{
const TArray<FPF2AbilityBoostRuleOption> RuleOptions = {};
Describe(TEXT("CanApplyAbilityBoost()"), [=, this]()
{
FPF2AbilityBoostRuleOptionMatcher Matcher(RuleOptions);
It(TEXT("returns `false` for all abilities"), [=, this, Matcher]()
{
for (const autoamp; AbilityScoreType : TEnumRange<EPF2CharacterAbilityScoreType>())
{
TestFalse(
FString::Format(TEXT("CanApplyAbilityBoost({0})"), { PF2EnumUtils::ToString(AbilityScoreType)}),
// Next line gets highlighted in red in Rider but compiles. Error is:
// Cannot convert 'this' argument from type 'FPF2AbilityBoostRuleOptionMatcher const' to type
// 'FPF2AbilityBoostRuleOptionMatcher': function is missing 'const' qualifier`
Matcher.CanApplyAbilityBoost(AbilityScoreType)
);
}
});
});
// ...
});
// ...
}
Это работает, хотя (но Matcher
это должно быть построено в каждом тестовом случае):
void FPF2AbilityBoostRuleOptionMatcherSpec::Define()
{
Describe(TEXT("when there are no rule options"), [=, this]()
{
const TArray<FPF2AbilityBoostRuleOption> RuleOptions = {};
Describe(TEXT("CanApplyAbilityBoost()"), [=, this]()
{
It(TEXT("returns `false` for all abilities"), [=, this]()
{
FPF2AbilityBoostRuleOptionMatcher Matcher(RuleOptions);
for (const autoamp; AbilityScoreType : TEnumRange<EPF2CharacterAbilityScoreType>())
{
TestFalse(
FString::Format(TEXT("CanApplyAbilityBoost({0})"), { PF2EnumUtils::ToString(AbilityScoreType)}),
Matcher.CanApplyAbilityBoost(AbilityScoreType)
);
}
});
});
});
// ...
});
// ...
}
Почему? Вызывается ли деструктор для этого объекта по какой-то причине до того, как на него ссылаются?
Комментарии:
1. Адресовано, @JaMiT. Немного доброты может пойти дальше 🙂
2. На самом деле здесь нет ничего, что выглядело бы особенно ужасно. Есть ли у вас в файле оптимизация? (Может объяснить, почему Matcher выглядит так, как будто он заполнен мусором). Это может быть что-то отрывочное, происходящее внутри одного из конструкторов Matcher или даже деструктора. Это также может быть частично объяснено, если
Descirbe
позволяет вызывать переданную функцию позже в строке, как только сопоставитель вышел за пределы области действия. Хотя это все еще не объясняет, почему ваш второй пример выходит из строя.3. Проверьте документацию для
It()
. Ваши симптомы хорошо соответствуют документации, в которой говорится, что второй параметр (ваша лямбда) может быть вызван после завершения выполненияIt()
; что второй параметр будет сохранен где-то для выполнения позже. Это соответствовало бы своего рода «ленивому» определению, в котором механизм записывает, как создавать спецификации, но генерирует каждый уровень детализации только по мере необходимости.4. Спасибо, @JaMiT! Такое ощущение, что переменные во внешней области выделяются стеком, а затем, когда они используются, они указывают на мусорную память. Я посмотрю, смогу ли я копнуть глубже, основываясь на том, что вы здесь указали.