From 40a3ab10b716a5fd5afa133adacafab496e0b94a Mon Sep 17 00:00:00 2001 From: Wolfgang Bangerth Date: Fri, 2 Apr 2021 15:21:33 -0600 Subject: [PATCH] Use std::unique_ptr to manage memory in AlignedVector. --- include/deal.II/base/aligned_vector.h | 106 ++++++++++++++------------ 1 file changed, 56 insertions(+), 50 deletions(-) diff --git a/include/deal.II/base/aligned_vector.h b/include/deal.II/base/aligned_vector.h index 7ad95848ee..f6e7b27017 100644 --- a/include/deal.II/base/aligned_vector.h +++ b/include/deal.II/base/aligned_vector.h @@ -35,6 +35,7 @@ #include #include +#include #include @@ -346,9 +347,9 @@ public: private: /** - * Pointer to actual class data. + * Pointer to actual data array. */ - T *data_begin; + std::unique_ptr data_begin; /** * Pointer to one past the last valid value. @@ -710,7 +711,7 @@ namespace internal template inline AlignedVector::AlignedVector() - : data_begin(nullptr) + : data_begin(nullptr, [](T *) { Assert(false, ExcInternalError()); }) , data_end(nullptr) , allocated_end(nullptr) {} @@ -719,7 +720,7 @@ inline AlignedVector::AlignedVector() template inline AlignedVector::AlignedVector(const size_type size, const T &init) - : data_begin(nullptr) + : data_begin(nullptr, [](T *) { Assert(false, ExcInternalError()); }) , data_end(nullptr) , allocated_end(nullptr) { @@ -739,21 +740,23 @@ inline AlignedVector::~AlignedVector() template inline AlignedVector::AlignedVector(const AlignedVector &vec) - : data_begin(nullptr) + : data_begin(nullptr, [](T *) { Assert(false, ExcInternalError()); }) , data_end(nullptr) , allocated_end(nullptr) { // copy the data from vec - reserve(vec.data_end - vec.data_begin); + reserve(vec.size()); data_end = allocated_end; - internal::AlignedVectorCopy(vec.data_begin, vec.data_end, data_begin); + internal::AlignedVectorCopy(vec.data_begin.get(), + vec.data_end, + data_begin.get()); } template inline AlignedVector::AlignedVector(AlignedVector &&vec) noexcept - : data_begin(vec.data_begin) + : data_begin(std::move(vec.data_begin)) , data_end(vec.data_end) , allocated_end(vec.allocated_end) { @@ -769,8 +772,10 @@ inline AlignedVector & AlignedVector::operator=(const AlignedVector &vec) { resize(0); - resize_fast(vec.data_end - vec.data_begin); - internal::AlignedVectorCopy(vec.data_begin, vec.data_end, data_begin); + resize_fast(vec.data_end - vec.data_begin.get()); + internal::AlignedVectorCopy(vec.data_begin.get(), + vec.data_end, + data_begin.get()); return *this; } @@ -782,11 +787,13 @@ AlignedVector::operator=(AlignedVector &&vec) noexcept { clear(); - data_begin = vec.data_begin; + // Move the actual data + data_begin = std::move(vec.data_begin); + + // Then also steal the other pointers and clear them in the original object: data_end = vec.data_end; allocated_end = vec.allocated_end; - vec.data_begin = nullptr; vec.data_end = nullptr; vec.allocated_end = nullptr; @@ -805,17 +812,17 @@ AlignedVector::resize_fast(const size_type size_in) // call destructor on fields that are released. doing it backward // releases the elements in reverse order as compared to how they were // created - while (data_end != data_begin + size_in) + while (data_end != data_begin.get() + size_in) (--data_end)->~T(); } reserve(size_in); - data_end = data_begin + size_in; + data_end = data_begin.get() + size_in; // need to still set the values in case the class is non-trivial because // virtual classes etc. need to run their (default) constructor if (std::is_trivial::value == false && size_in > old_size) dealii::internal::AlignedVectorDefaultInitialize( - size_in - old_size, data_begin + old_size); + size_in - old_size, data_begin.get() + old_size); } @@ -830,16 +837,16 @@ AlignedVector::resize(const size_type size_in) // call destructor on fields that are released. doing it backward // releases the elements in reverse order as compared to how they were // created - while (data_end != data_begin + size_in) + while (data_end != data_begin.get() + size_in) (--data_end)->~T(); } reserve(size_in); - data_end = data_begin + size_in; + data_end = data_begin.get() + size_in; // finally set the desired init values if (size_in > old_size) dealii::internal::AlignedVectorDefaultInitialize( - size_in - old_size, data_begin + old_size); + size_in - old_size, data_begin.get() + old_size); } @@ -854,17 +861,17 @@ AlignedVector::resize(const size_type size_in, const T &init) // call destructor on fields that are released. doing it backward // releases the elements in reverse order as compared to how they were // created - while (data_end != data_begin + size_in) + while (data_end != data_begin.get() + size_in) (--data_end)->~T(); } reserve(size_in); - data_end = data_begin + size_in; + data_end = data_begin.get() + size_in; // finally set the desired init values if (size_in > old_size) dealii::internal::AlignedVectorSet(size_in - old_size, init, - data_begin + old_size); + data_begin.get() + old_size); } @@ -873,8 +880,8 @@ template inline void AlignedVector::reserve(const size_type size_alloc) { - const size_type old_size = data_end - data_begin; - const size_type allocated_size = allocated_end - data_begin; + const size_type old_size = data_end - data_begin.get(); + const size_type allocated_size = allocated_end - data_begin.get(); if (size_alloc > allocated_size) { // if we continuously increase the size of the vector, we might be @@ -888,22 +895,23 @@ AlignedVector::reserve(const size_type size_alloc) // allocate and align along 64-byte boundaries (this is enough for all // levels of vectorization currently supported by deal.II) - T *new_data; - Utilities::System::posix_memalign(reinterpret_cast(&new_data), - 64, - size_actual_allocate); + T *new_data_ptr; + Utilities::System::posix_memalign( + reinterpret_cast(&new_data_ptr), 64, size_actual_allocate); + std::unique_ptr new_data(new_data_ptr, [](T *ptr) { + std::free(ptr); + }); // copy data in case there was some content before and release the old // memory with the function corresponding to the one used for allocating std::swap(data_begin, new_data); - data_end = data_begin + old_size; - allocated_end = data_begin + new_size; - if (data_end != data_begin) + data_end = data_begin.get() + old_size; + allocated_end = data_begin.get() + new_size; + if (data_end != data_begin.get()) { - dealii::internal::AlignedVectorMove(new_data, - new_data + old_size, - data_begin); - free(new_data); + dealii::internal::AlignedVectorMove(new_data.get(), + new_data.get() + old_size, + data_begin.get()); } else Assert(new_data == nullptr, ExcInternalError()); @@ -921,10 +929,8 @@ AlignedVector::clear() if (data_begin != nullptr) { if (std::is_trivial::value == false) - while (data_end != data_begin) + while (data_end != data_begin.get()) (--data_end)->~T(); - - free(data_begin); } data_begin = nullptr; data_end = nullptr; @@ -992,7 +998,7 @@ inline void AlignedVector::fill() { dealii::internal::AlignedVectorDefaultInitialize(size(), - data_begin); + data_begin.get()); } @@ -1001,7 +1007,7 @@ template inline void AlignedVector::fill(const T &value) { - dealii::internal::AlignedVectorSet(size(), value, data_begin); + dealii::internal::AlignedVectorSet(size(), value, data_begin.get()); } @@ -1021,7 +1027,7 @@ template inline bool AlignedVector::empty() const { - return data_end == data_begin; + return data_end == data_begin.get(); } @@ -1030,7 +1036,7 @@ template inline typename AlignedVector::size_type AlignedVector::size() const { - return data_end - data_begin; + return data_end - data_begin.get(); } @@ -1039,7 +1045,7 @@ template inline typename AlignedVector::size_type AlignedVector::capacity() const { - return allocated_end - data_begin; + return allocated_end - data_begin.get(); } @@ -1068,7 +1074,7 @@ template inline typename AlignedVector::pointer AlignedVector::data() { - return data_begin; + return data_begin.get(); } @@ -1077,7 +1083,7 @@ template inline typename AlignedVector::const_pointer AlignedVector::data() const { - return data_begin; + return data_begin.get(); } @@ -1086,7 +1092,7 @@ template inline typename AlignedVector::iterator AlignedVector::begin() { - return data_begin; + return data_begin.get(); } @@ -1104,7 +1110,7 @@ template inline typename AlignedVector::const_iterator AlignedVector::begin() const { - return data_begin; + return data_begin.get(); } @@ -1126,7 +1132,7 @@ AlignedVector::save(Archive &ar, const unsigned int) const size_type vec_size(size()); ar & vec_size; if (vec_size > 0) - ar &boost::serialization::make_array(data_begin, vec_size); + ar &boost::serialization::make_array(data_begin.get(), vec_size); } @@ -1142,8 +1148,8 @@ AlignedVector::load(Archive &ar, const unsigned int) if (vec_size > 0) { reserve(vec_size); - ar &boost::serialization::make_array(data_begin, vec_size); - data_end = data_begin + vec_size; + ar &boost::serialization::make_array(data_begin.get(), vec_size); + data_end = data_begin.get() + vec_size; } } @@ -1154,7 +1160,7 @@ inline typename AlignedVector::size_type AlignedVector::memory_consumption() const { size_type memory = sizeof(*this); - for (const T *t = data_begin; t != data_end; ++t) + for (const T *t = data_begin.get(); t != data_end; ++t) memory += dealii::MemoryConsumption::memory_consumption(*t); memory += sizeof(T) * (allocated_end - data_end); return memory; -- 2.39.5