Skip to content

Commit 3488a76

Browse files
committed
buffer: implement move semantics properly
Default implementations of move semantics are not suitable - let's implement proper ones. Along the way, do not accept allocator in constructor by reference since buffer stores its own copy - let's consumer it, and to do so, we should accept rvalue reference there. Part of #110
1 parent 97807d9 commit 3488a76

File tree

1 file changed

+35
-7
lines changed

1 file changed

+35
-7
lines changed

src/Buffer/Buffer.hpp

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,12 @@ class Buffer
115115
* to the next byte after the last valid byte in block.
116116
* */
117117
bool isEndOfBlock(const char *ptr);
118+
/** Delete blocks and release occupied memory. */
119+
void releaseBlocks(void)
120+
{
121+
while (!m_blocks.isEmpty())
122+
delBlock(&m_blocks.first());
123+
}
118124

119125
public:
120126
/** =============== Convenient wrappers =============== */
@@ -265,11 +271,35 @@ class Buffer
265271

266272
/** =============== Buffer definition =============== */
267273
/** Copy of any kind is disabled. Move is allowed. */
268-
Buffer(const allocator& all = allocator());
274+
Buffer(allocator &&all = allocator());
269275
Buffer(const Buffer& buf) = delete;
270276
Buffer& operator = (const Buffer& buf) = delete;
271-
Buffer(Buffer &&buf) noexcept = default;
272-
Buffer &operator=(Buffer &&buf) noexcept = default;
277+
Buffer(Buffer &&other) noexcept
278+
{
279+
/* Call move assignment operator. */
280+
*this = std::forward<Buffer>(other);
281+
}
282+
Buffer &operator=(Buffer &&other)
283+
{
284+
if (this == &other)
285+
return *this;
286+
287+
m_blocks = std::move(other.m_blocks);
288+
/*
289+
* Release blocks of `other` right on the move because
290+
* we are going to move its allocator as well and we
291+
* shouldn't use it after it is moved.
292+
*/
293+
other.releaseBlocks();
294+
m_all = std::move(other.m_all);
295+
296+
m_iterators = std::move(other.m_iterators);
297+
m_begin = other.m_begin;
298+
other.m_begin = nullptr;
299+
m_end = other.m_end;
300+
other.m_end = nullptr;
301+
return *this;
302+
}
273303
~Buffer() noexcept;
274304

275305
/**
@@ -648,7 +678,7 @@ Buffer<N, allocator>::iterator_common<LIGHT>::moveBackward(size_t step)
648678
}
649679

650680
template <size_t N, class allocator>
651-
Buffer<N, allocator>::Buffer(const allocator &all) : m_all(all)
681+
Buffer<N, allocator>::Buffer(allocator &&all) : m_all(std::forward<allocator>(all))
652682
{
653683
static_assert((N & (N - 1)) == 0, "N must be power of 2");
654684
static_assert(allocator::REAL_SIZE % alignof(Block) == 0,
@@ -666,9 +696,7 @@ Buffer<N, allocator>::Buffer(const allocator &all) : m_all(all)
666696
template <size_t N, class allocator>
667697
Buffer<N, allocator>::~Buffer() noexcept
668698
{
669-
/* Delete blocks and release occupied memory. */
670-
while (!m_blocks.isEmpty())
671-
delBlock(&m_blocks.first());
699+
releaseBlocks();
672700
}
673701

674702
template <size_t N, class allocator>

0 commit comments

Comments
 (0)