0

我最近看到这样的代码:

// 3rd Party API: (paraphrased)
void APIResetIterator(int ID); // reset iterator for call to next()
Mogrifier* APINext(int ID); // User must delete pointer returned

...

typedef std::unique_ptr<Mogrifier> MogPtr;

...

const it listID = 42;
APIResetIterator(listID);
MogPtr elem;
while (elem.reset(APINext(listID)), elem) {
  // use elem
}

这是一个好主意吗?它有效吗?


我将添加相应的 for 循环以方便参考:

for (MogPtr elem(APINext(listID)); elem; elem.reset(APINext(listID));) {
  // use elem
}

...也没有让我觉得真正的最佳...

4

5 回答 5

2

正如其他答案中所说:这在技术上是可以的,并且可以按预期工作。但是你质疑它实际上表明这不是一个好主意,因为它缺乏可读性。

这是一种伪装的 for 循环,类似于这个:

int i = -1;
while (++i, i<10) { something(i); }

换句话说,您可以通过实际使用 for 循环使其更清晰:

for (MogPtr elem{APINext(listID)}; elem != nullptr; elem.reset(APINext(listID)))
{
  // use elem
}

唯一的问题是您必须输入APINext两次(震惊!),这可能是有人以现在的方式编写它的原因。

经验教训:可读性胜过懒惰。

编辑: imo 输入两次实际上是一件好事APINext(listID),因为它清楚地表明第一次实际上是初始化,其他时候是重新分配。

Edit2:这种Iterator/Next()组合在 C++ 中可能看起来有点不寻常,因为 C++ 标准库迭代器使用运算符重载。在没有运算符重载的 Java 和其他语言中,这是做事的正常方式。如果你愿意,你可以编写一个简单的 C++ 风格的前向迭代器来包装 API 调用:

class MogrifierIterator {
  MogPtr ptr_;
  int listID_
public:
  MogrifierIterator() : ptr_(nullptr) {} //end-Iterator
  explicit MogrifierIterator(int listID) : ptr(nullptr), listID_(listID)  { 
    APIResetIterator(listID_); 
    ptr_.reset(APINext(listID_));
  }

  Mogrifier& operator*() { return *ptr_; }
  Mogrifier* operator->() { return ptr_.get(); }
  MogrifierIterator& operator++() { ptr_.reset(APINext(listID_)); return *this; }

  bool operator==(MogrifierIterator const& other)
  { return (ptr_==other.ptr_) && (ptr_ == nullptr || listID_ == other.listID_); }
};

//...
for (MogrifierIterator it(listID); it != Mogrifieriterator(); ++it)
{
  it->mogrify();
}

它不完整,我没有测试它,它可能包含错误,但你明白了要点:)

于 2013-02-22T10:53:09.860 回答
1

它应该工作。有点棘手,不太明显,但除此之外就可以了。也许使用 for 循环会使代码更清晰。

于 2013-02-22T10:38:16.717 回答
1

它有效吗?好吧,它应该,语法是有效的:指针被重置为返回的值APINext(),然后NULLwhile条件中对其进行测试。

这是一个好主意吗?这是一个品味问题,但很多人(包括我)不喜欢那种代码。它可能是合法且有效的,但不是那么清楚,需要一段时间才能理解。对我来说,代码的可读性非常重要,而这个特定的代码并不是可读性的好例子。

于 2013-02-22T10:39:27.350 回答
0

它确实有效,但它是否比 for 循环更好是另一个争论。在这种情况下,它避免了重复代码,因为获取第一个元素与获取下一个元素相同(除了APIResetIterator(listID);)。所以这将是关于惯用编码(for循环)或避免双重代码(获取第一个元素并获取下一个元素)。

我的建议是在 for 循环中使用迭代器,但在这种情况下这可能不是那么好。

于 2013-02-22T10:39:57.090 回答
0

也许我们应该把它写成:

template<class SPT, typename P>
SPT& reset(SPT& smartPtr, P ptr) {
  smartPtr.reset(ptr);
  return smartPtr;
}

for (MogPtr elem; reset(elem, APINext(listID));) {
  // use elem
}
于 2013-02-22T10:51:42.690 回答