I have some code that creates a vector of strings in one function, converts that to a TArray<FString>
, assigns it to the member variable of an object, and adds that object to a TArray
, something like below:
void MyMethod() {
std::vector<std::string> vec = GetVec();
TArray<FString> arr = VecStrToTArrFStr(vec);
MyObject obj;
obj.value = arr;
this->Objects.Add(obj);
}
Where the function VecStrToTArrFStr
is as follows:
inline TArray<FString> VecStrToTArrFStr(std::vector<std::string> &vec) {
TArray<FString> arr;
arr.SetNumUninitialized(vec.size());
for (auto &item : vec) {
arr.Add(FString(UTF8_TO_TCHAR(item.c_str())));
}
return arr;
}
This issue occurs on this line:
this->Objects.Add(obj);
For some reason, copying the array throws a segfault. Specifically, it gives this call stack:
__memcpy_avx_unaligned (@7fffec5b4ea0..7fffec5b5226:173)
FGenericPlatformMemory::Memcpy(void*, void const*, unsigned long) (/UnrealEngine/Engine/Source/Runtime/Core/Public/GenericPlatform/GenericPlatformMemory.h:348)
FMemory::Memcpy(void*, void const*, unsigned long) (/UnrealEngine/Engine/Source/Runtime/Core/Public/HAL/UnrealMemory.h:124)
TEnableIf<TIsBitwiseConstructible<wchar_t, wchar_t>::Value, void>::Type ConstructItems<wchar_t, wchar_t>(void*, wchar_t const*, int) (/UnrealEngine/Engine/Source/Runtime/Core/Public/Templates/MemoryOps.h:137)
void TArray<wchar_t, FDefaultAllocator>::CopyToEmpty<wchar_t>(wchar_t const*, int, int, int) (/UnrealEngine/Engine/Source/Runtime/Core/Public/Containers/Array.h:2508)
TArray<wchar_t, FDefaultAllocator>::TArray(TArray<wchar_t, FDefaultAllocator> const&) (/UnrealEngine/Engine/Source/Runtime/Core/Public/Containers/Array.h:338)
FString::FString(FString const&) (/UnrealEngine/Engine/Source/Runtime/Core/Public/Containers/UnrealString.h:73)
TEnableIf<!(TIsBitwiseConstructible<FString, FString>::Value), void>::Type ConstructItems<FString, FString>(void*, FString const*, int) (/UnrealEngine/Engine/Source/Runtime/Core/Public/Templates/MemoryOps.h:126)
void TArray<FString, FDefaultAllocator>::CopyToEmpty<FString>(FString const*, int, int, int) (/UnrealEngine/Engine/Source/Runtime/Core/Public/Containers/Array.h:2508)
TArray<FString, FDefaultAllocator>::TArray(TArray<FString, FDefaultAllocator> const&) (/UnrealEngine/Engine/Source/Runtime/Core/Public/Containers/Array.h:338)
MyObject::MyObject(MyObject const&) (MyObject.h)
int TArray<MyObject, FDefaultAllocator>::Emplace<MyObject const&>(MyObject const&&&) (/UnrealEngine/Engine/Source/Runtime/Core/Public/Containers/Array.h:1843)
TArray<MyObject, FDefaultAllocator>::Add(MyObject const&) (/UnrealEngine/Engine/Source/Runtime/Core/Public/Containers/Array.h:1916)
Everything runs perfectly fine if I change MyObject.value
to be of type std::vector<std::string>
and just assign it the vec
, but attempting to assign it a TArray<FString>
throws a segfault.
What could be causing this? Does it have something to do with how I'm creating my FString
objects, or how I'm creating my TArray
? Is UE4 doing some garbage collection on the TArray
in VecStrToArrFStr
or something?
You've populated the array with garbage FString
objects; when you call TArray::Add
, the FString
copy constructor attempts to perform a bitwise copy on its members resulting in dereferencing a garbage pointer, causing a sigsegv.
To resolve, remove the call to SetNumUninitialized
; it doesn't do what you think it does. This call doesn't just reserve the space, you're actually adding the specified number of garbage (uninitialised) FStrings
into the array, then putting the "real" ones on the end of them. Have a look at what state your array ends up in after the call to VecStrToTArrFStr
.
https://api.unrealengine.com/INT/API/Runtime/Core/Containers/TArray/SetNumUninitialized/index.html