Assume I have a C++ iterator that not only traverses a data structure but also applies a transformation to the elements when it is dereferenced.
As a real-world example, here's an iterator that goes over the pixels in a bitmap, transforming the bitmap-specific pixel format into a convenient structure:
class ConstPixelIterator {
public: struct Pixel {
float Red;
float Green;
float Blue;
float Alpha;
};
public: ConstPixelIterator(const Bitmap &bitmap);
// ...standard iterator functionality...
public: Pixel operator *() {
// Read from memory and convert pixel format-specific bytes into Pixel structure
}
};
Now if I wanted to implement a non-const iterator (i.e. let the user modify pixels), what is the best way to go about this?
Some ideas I considered:
I could put accessor methods in the Pixel
structure instead of plain fields and give it a reference to its owner to phone home. This would however mean that if the user changed R,G,B and A, I would convert the pixel into the bitmap's pixel format 4 times and write to memory 4 times.
I could return a Pixel reference from the iterator and provide it with an Update()
method that needs to be called if the pixel was changed. This would be non-intuitive and risk users forgetting to call Update
.
I could always return the Pixel
by value and provide a special assignment operator. Does break the standard iterator pattern - assigning to an iterator without dereferencing should move the iterator, not update the element it is pointing at
We've got an existing example in std::vector<bool>::iterator
- that has to pull a few tricks to write to a single bit.
One solution is to return a ProxyPixel
. It keeps a reference to the original pixel. You stated that updating R,G,B,A may cause 4 writes. That's true, and understandable. After the first write of just R, the underlying image should have an updated R value after all.
Or are you happy to accept an eventual update? In that case, you may delay the write-back to ProxyPixel::~ProxyPixel
. Yes, the underlying image will then be temporarily out of sync as the proxy pixel is being changed, but it would be more efficient. A reasonable tradeoff.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With