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
}

唯一のことは、2 回入力しなければならないことですAPINext(ショック!) これが、おそらく誰かが現在のように書いた理由です。

得られた教訓: 読みやすさは怠惰よりも重要です。

編集: imo、実際には2回入力するのは良いことです.1APINext(listID)回目は実際には初期化であり、2回目は再割り当てであることが明確になるからです.

Edit2: C++ 標準ライブラリの反復子は演算子のオーバーロードで動作するため、このIterator/Next()組み合わせは C++ では少し変わっているように見えるかもしれません。演算子のオーバーロードがない Java やその他の言語では、これが通常の方法です。必要に応じて、API 呼び出しをラップする単純な C++ スタイルの前方反復子を作成できます。

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

それは機能しますか?そうですね、構文は有効です。ポインタは、によって返される値にリセットされ、条件でAPINext()テストされます。NULLwhile

これは良い考えですか?それは好みの問題ですが、多くの人(私を含む)はその種のコードを好きではありません。それは合法で機能しているかもしれませんが、それはそれほど明確ではなく、理解するのに時間がかかります。私にとって、コードの可読性は非常に重要であり、この特定のコードは可読性の良い例ではありません。

于 2013-02-22T10:39:27.350 に答える
1

それはうまくいくはずです。少しトリッキーで、あまり明白ではありませんが、それ以外の場合は機能します。おそらく for サイクルを使用すると、コードがより明確になります。

于 2013-02-22T10:38:16.717 に答える
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 に答える