In part 6 we modified the buffer to work by storing bytes, this means that the compiler treats those bytes as raw data and not as the objects that data represents. This means that we also had to do the following:
RingBuffer(const RingBuffer&) = delete;
RingBuffer(RingBuffer&&) = delete;
RingBuffer& operator=(const RingBuffer&) = delete;
RingBuffer& operator=(RingBuffer&&) = delete;
Which effectively makes memberwise copy/move meaningless. Remember, we are using a raw byte buffer and placement new. Because of this we are managing object lifetimes manually. Usually a default compiler-generated copy would simply perform bitwise copy of the std::byte array and this creates a few problems. Bitwise copying does not call the actual copy constructors of the T objects stored in the buffer, so if T is a complex type such as std::string, copying its bits without calling the constructor would result in a shallow copy leading to a corrupted state or dangling pointers, if this isn’t bad enough, there is also wasted effort as the compiler would copy the entire buffer, including the empty slots that have not been constructed yet. Let us explore some concepts in more detail.
In
We closed
In
In
In
Hello! If you recall from the previous series, we built a program that handled text input, stored numbers into a vector and performed calculations. However there were some concepts in there that we used, but that I didn’t really explain. I am referring to iterators. In this new series I aim to go over what they are, how they work and how to use them, so get ready because it will be a bumpy ride and as usual, we will have to build our way there because fundamentals are always important.