Nullable.Reset fix, killing inlining

This commit is contained in:
Mateusz Karbowiak
2024-10-07 12:17:23 +02:00
parent 541ca67a06
commit f56207f1a4

View File

@@ -24,17 +24,6 @@ private:
}; };
bool _hasValue; bool _hasValue;
/// <summary>
/// Ends the lifetime of the wrapped value by calling its destructor, if the lifetime has not ended yet. Otherwise, does nothing.
/// </summary>
FORCE_INLINE void KillOld()
{
if (_hasValue)
{
_value.~T();
}
}
public: public:
/// <summary> /// <summary>
/// Initializes <see cref="Nullable{T}"/> by setting the wrapped value to null. /// Initializes <see cref="Nullable{T}"/> by setting the wrapped value to null.
@@ -48,7 +37,10 @@ public:
~Nullable() ~Nullable()
{ {
KillOld(); if (_hasValue)
{
_value.~T();
}
} }
/// <summary> /// <summary>
@@ -104,7 +96,10 @@ public:
template<typename U = T, typename = typename TEnableIf<TIsCopyConstructible<U>::Value>::Type> template<typename U = T, typename = typename TEnableIf<TIsCopyConstructible<U>::Value>::Type>
auto operator=(const T& value) -> Nullable& auto operator=(const T& value) -> Nullable&
{ {
KillOld(); if (_hasValue)
{
_value.~T();
}
new (&_value) T(value); // Placement new (copy constructor) new (&_value) T(value); // Placement new (copy constructor)
_hasValue = true; _hasValue = true;
@@ -117,7 +112,10 @@ public:
/// </summary> /// </summary>
auto operator=(T&& value) noexcept -> Nullable& auto operator=(T&& value) noexcept -> Nullable&
{ {
KillOld(); if (_hasValue)
{
_value.~T();
}
new (&_value) T(MoveTemp(value)); // Placement new (move constructor) new (&_value) T(MoveTemp(value)); // Placement new (move constructor)
_hasValue = true; _hasValue = true;
@@ -131,12 +129,16 @@ public:
template<typename U = T, typename = typename TEnableIf<TIsCopyConstructible<U>::Value>::Type> template<typename U = T, typename = typename TEnableIf<TIsCopyConstructible<U>::Value>::Type>
auto operator=(const Nullable& other) -> Nullable& auto operator=(const Nullable& other) -> Nullable&
{ {
KillOld(); if (_hasValue)
{
_value.~T();
}
if (other._hasValue) if (other._hasValue)
{ {
new (&_value) T(other._value); // Placement new (copy constructor) new (&_value) T(other._value); // Placement new (copy constructor)
} }
_hasValue = other._hasValue; // Set the flag AFTER the value is copied. _hasValue = other._hasValue; // Set the flag AFTER the value is copied.
return *this; return *this;
@@ -152,14 +154,19 @@ public:
return *this; return *this;
} }
KillOld();
if (_hasValue) if (_hasValue)
{
_value.~T();
}
if (other._hasValue)
{ {
new (&_value) T(MoveTemp(other._value)); // Placement new (move constructor) new (&_value) T(MoveTemp(other._value)); // Placement new (move constructor)
other.Reset(); other._value.~T(); // Kill the old value in the source object.
other._hasValue = false;
} }
_hasValue = other._hasValue; // Set the flag AFTER the value is moved. _hasValue = other._hasValue; // Set the flag AFTER the value is moved.
return *this; return *this;
@@ -235,7 +242,10 @@ public:
/// <param name="value">The value to be moved.</param> /// <param name="value">The value to be moved.</param>
FORCE_INLINE void SetValue(T&& value) noexcept FORCE_INLINE void SetValue(T&& value) noexcept
{ {
KillOld(); if (_hasValue)
{
_value.~T();
}
new (&_value) T(MoveTemp(value)); // Placement new (move constructor) new (&_value) T(MoveTemp(value)); // Placement new (move constructor)
_hasValue = true; // Set the flag AFTER the value is moved. _hasValue = true; // Set the flag AFTER the value is moved.
@@ -279,8 +289,13 @@ public:
/// </summary> /// </summary>
FORCE_INLINE void Reset() FORCE_INLINE void Reset()
{ {
if (!_hasValue)
{
return;
}
_hasValue = false; // Reset the flag BEFORE the value is (potentially) destructed. _hasValue = false; // Reset the flag BEFORE the value is (potentially) destructed.
KillOld(); _value.~T();
} }
/// <summary> /// <summary>