[core] Fix issues in unique_any

* Eliminate unnecessary temporary in VTableStack::move, which also fixes calling the destructor on the incorrect instance
* Make move consistent: it destructs the src, not the dest, which is always empty
* delete doesn't need a null guard
* Conversions to void* don't need a cast
This commit is contained in:
John Firebaugh
2018-06-18 16:24:58 -07:00
parent f3341dd589
commit d176e9bb46
2 changed files with 42 additions and 14 deletions

View File

@@ -135,15 +135,12 @@ private:
template <typename ValueType>
struct VTableHeap : public VTable {
void move(Storage&& src, Storage& dest) override {
destroy(dest);
dest.dynamic = src.dynamic;
src.dynamic = nullptr;
}
void destroy(Storage& s) override {
if (s.dynamic) {
delete reinterpret_cast<ValueType*>(s.dynamic);
}
s.dynamic = nullptr;
delete reinterpret_cast<ValueType*>(s.dynamic);
}
const std::type_info& type() override {
@@ -154,9 +151,8 @@ private:
template <typename ValueType>
struct VTableStack : public VTable {
void move(Storage&& src, Storage& dest) override {
auto srcValue = reinterpret_cast<ValueType&&>(src.stack);
new (static_cast<void*>(&dest.stack)) ValueType(std::move(srcValue));
srcValue.~ValueType();
new (&dest.stack) ValueType(std::move(reinterpret_cast<ValueType&>(src.stack)));
destroy(src);
}
void destroy(Storage& s) override {
@@ -178,13 +174,13 @@ private:
template <typename ValueType, typename _Vt>
std::enable_if_t<AllocateOnStack<_Vt>::value>
createStorage(ValueType&& value) {
new (static_cast<void*>(&storage.stack)) _Vt(std::forward<ValueType>(value));
new (&storage.stack) _Vt(std::forward<ValueType>(value));
}
template <typename ValueType, typename _Vt>
std::enable_if_t<!AllocateOnStack<_Vt>::value>
createStorage(ValueType&& value) {
storage.dynamic = static_cast<void*>(new _Vt(std::forward<ValueType>(value)));
storage.dynamic = new _Vt(std::forward<ValueType>(value));
}
template <typename ValueType>

View File

@@ -10,15 +10,14 @@ public:
str[0] = 'a';
}
TestType(unique_any& p) : TestType() {
p = std::unique_ptr<TestType>(this);
}
//Detect moves
TestType(TestType&& t): i1(t.i1+1), i2(t.i2+2) {
str[0] = t.str[0]+1;
}
TestType(const TestType&) = delete;
TestType& operator=(const TestType&) = delete;
int i1;
int i2;
char str[256];
@@ -88,6 +87,39 @@ TEST(UniqueAny, BasicTypes_Move) {
}
TEST(UniqueAny, SmallType) {
struct T {
T(int32_t* p_) : p(p_) {
(*p)++;
}
T(T&& t) noexcept : p(t.p) {
(*p)++;
}
~T() {
(*p)--;
}
T(const T&) = delete;
T& operator=(const T&) = delete;
int32_t* p;
};
int32_t p = 0;
{
unique_any u1 = unique_any(T(&p));
EXPECT_EQ(p, 1);
auto u2(std::move(u1));
EXPECT_EQ(p, 1);
}
EXPECT_EQ(p, 0);
}
TEST(UniqueAny, LargeType) {
TestType t1;
unique_any u1 = unique_any(std::move(t1));