是否可以在C ++中使用转换迭代器?

时间:2015-02-02 09:44:03

标签: c++ iterator type-conversion conventions updating

假设我有一个C ++迭代器,它不仅遍历数据结构,而且在取消引用时也对元素应用转换。

作为一个真实的例子,这里有一个迭代器遍历位图中的像素,将位图特定的像素格式转换为方便的结构:

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
  }

};

现在,如果我想实现一个非const迭代器(即让用户修改像素),那么最好的方法是什么?

我考虑过的一些想法:

  • 我可以将访问器方法放在Pixel结构而不是普通字段中,并为其所有者提供电话回家的参考。 但这意味着如果用户更改了R,G,B和A,我会将像素转换为位图的像素格式4次,然后写入内存4次。

  • 我可以从迭代器返回一个Pixel引用,并为其提供一个Update()方法,如果像素被更改,则需要调用该方法。 这是非直观的,风险用户忘记致电Update

  • 我总是可以按值返回Pixel并提供一个特殊的赋值运算符。 是否破坏标准迭代器模式 - 在没有解除引用的情况下分配给迭代器应该移动迭代器,而不是更新它指向的元素

3 个答案:

答案 0 :(得分:3)

我们在std::vector<bool>::iterator中有一个现有示例 - 必须通过一些技巧来写入一个位。

一种解决方案是返回ProxyPixel。它保留对原始像素的引用。您声明更新R,G,B,A可能会导致4次写入。这是真的,也是可以理解的。在第一次写入R之后,底层图像应该具有更新的R值。

或者您是否乐意接受最终更新?在这种情况下,您可以将回写延迟到ProxyPixel::~ProxyPixel。是的,随着代理像素的更改,底层图像将暂时不同步,但效率会更高。合理的权衡。

答案 1 :(得分:0)

  

我可以在Pixel结构中放置访问器方法而不是普通字段,并为其所有者提供电话回家的参考。然而,这意味着如果用户改变了R,G,B和A,我会将像素转换为位图的像素格式4次并写入内存4次。

这推动了demeter的规律(像素不应该改变位图来设置它自己的值);你不应该这样做。

  

我可以从迭代器返回一个Pixel引用,并为它提供一个Update()方法,如果像素被更改,则需要调用该方法。这将是非直观的,并且风险用户忘记致电更新。

这是一个糟糕的界面,因为在不记住内容的情况下正确使用会很棘手。它也违反了demeter的布局(你不应该通过像素更新位图)。

  

我总是可以按值返回Pixel并提供一个特殊的赋值运算符。是否打破标准迭代器模式 - 在没有解除引用的情况下分配给迭代器应该移动迭代器,而不是更新它指向的元素

不要这样做;它违反了最不惊讶的原则。

考虑使像素独立于位图(即像素不知道位图是什么)。

您应该能够轻松地将(有效)值设置到像素中(使用字段或Update(R, G, B, A)或类似的访问器)并让位图知道像素是什么以及如何从像素更新自身,其中一个(或多个):

void Bitmap::Update(int x, int y, const Pixel& p);
void Bitmap::Fill(const Pixel& p);
void Bitmap::SetRange(SomeRangeObject r, const Pixel& p);

这样,对像素的更新操作将需要以下步骤:

  • 从位图获取像素
  • 根据需要更新/转换像素
  • 从像素更新位图

这不包括谁知道像素的位置(它们可能不应该是像素本身的一部分),但这是一个开始。

使用此实现,您的相互依赖性保持较低(更新位图像素的功能保留在位图中,而不是像素中),并且迭代模型很简单(与标准迭代器相同)。

答案 2 :(得分:0)

Pixel结构的成员可以实现为属性。

这可以让你写出像

这样的东西
iter->r = 0;

它不允许您将像素结构发送到那些函数 期待它是'straigtforward'

在c ++中实现属性很简单,例如参见here

多次写入内存应该不是问题,因为它会缓存本地

相关问题