BLI: add Array constructor that does not initialize non-trivial types

This should rarely be necessary, but I have a use case coming up soon.
This commit is contained in:
2020-06-30 15:58:14 +02:00
parent 5b03f49302
commit 37820651bb
3 changed files with 61 additions and 2 deletions

View File

@@ -27,8 +27,7 @@
* blender::Array should usually be used instead of blender::Vector whenever the number of elements
* is known at construction time. Note however, that blender::Array will default construct all
* elements when initialized with the size-constructor. For trivial types, this does nothing. In
* all other cases, this adds overhead. If this becomes a problem, a different constructor which
* does not do default construction can be added.
* all other cases, this adds overhead.
*
* A main benefit of using Array over Vector is that it expresses the intent of the developer
* better. It indicates that the size of the data structure is not expected to change. Furthermore,
@@ -130,6 +129,24 @@ class Array {
uninitialized_fill_n(m_data, m_size, value);
}
/**
* Create a new array with uninitialized elements. The caller is responsible for constructing the
* elements. Moving, copying or destructing an Array with uninitialized elements invokes
* undefined behavior.
*
* This should be used very rarely. Note, that the normal size-constructor also does not
* initialize the elements when T is trivially constructible. Therefore, it only makes sense to
* use this with non trivially constructible types.
*
* Usage:
* Array<std::string> my_strings(10, NoInitialization());
*/
Array(uint size, NoInitialization)
{
m_size = size;
m_data = this->get_buffer_for_size(size);
}
Array(const Array &other) : m_allocator(other.m_allocator)
{
m_size = other.size();

View File

@@ -242,6 +242,13 @@ template<size_t Size, size_t Alignment> class alignas(Alignment) AlignedBuffer {
}
};
/**
* This can be used by container constructors. A parameter of this type should be used to indicate
* that the constructor does not construct the elements.
*/
class NoInitialization {
};
} // namespace blender
#endif /* __BLI_MEMORY_UTILS_HH__ */

View File

@@ -124,3 +124,38 @@ TEST(array, TrivialTypeSizeConstructor)
EXPECT_EQ(*ptr, magic);
delete array;
}
struct ConstructibleType {
char value;
ConstructibleType()
{
value = 42;
}
};
TEST(array, NoInitializationSizeConstructor)
{
using MyArray = Array<ConstructibleType>;
AlignedBuffer<sizeof(MyArray), alignof(MyArray)> buffer;
char *buffer_ptr = (char *)buffer.ptr();
memset(buffer_ptr, 100, sizeof(MyArray));
/* Doing this to avoid some compiler optimization. */
for (uint i : IndexRange(sizeof(MyArray))) {
EXPECT_EQ(buffer_ptr[i], 100);
}
{
MyArray &array = *new (buffer.ptr()) MyArray(1, NoInitialization());
EXPECT_EQ(array[0].value, 100);
array.clear_without_destruct();
array.~Array();
}
{
MyArray &array = *new (buffer.ptr()) MyArray(1);
EXPECT_EQ(array[0].value, 42);
array.~Array();
}
}