Smart pointer test in a while loop: use the comma operator?

为君一笑 提交于 2019-12-25 04:57:27

问题


I recently saw code like this:

// 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
}

Is this a good idea? Does it work?


I'll add the corresponding for loop for easy reference:

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

... doesn't strike me as really optimal either ...


回答1:


As said in the other answers: This is technically ok and works as intended. But that you are questioning it actually shows that it's not a good idea, because it lacks readability.

This is sort of a disguised for-loop, similar to this one:

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

In other words, you can just make it clearer by actually using a for loop:

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

Only thing is that you have to type APINext twice (shock!) which is probably the reason why someone had written it the way it is now.

Lesson learned: Readability outweighs laziness.

Edit: imo it's actually a good thing to type APINext(listID) twice, because it makes clear that the first time it's actually an initialization, the other times, it's reassignment.

Edit2: The Iterator/Next() combination may look a bit unusual in C++, since C++ standard library iterators work with operator overloading. In Java and other languages without operator overloading, this is the normal way to do things. If you want, you can write a simple C++ style forward iterator wrapping the API calls:

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();
}

It's not complete, I have not tested it and it may contain errors, but you get the gist :)




回答2:


It should work. A bit tricky and not too obvious but otherwise does the job. Maybe using a for cycle would make the code clearer.




回答3:


Does it work? Well, it should, the syntax is valid: the pointer is reset to the value returned by APINext(), then it's tested for NULL in the while condition.

Is this a good idea? It's a matter of taste, but lots of people (including me) don't like that kind of code. It might be legal and working, but it is not that clear, takes a time to understand. For me, code readability very important and this particular code isn't good example of readability.




回答4:


It definitively works, but whether it is better than a for loop is another debate. In this case, it avoids double code because getting the first element is the same as getting the next element (except for the APIResetIterator(listID);). So this would be about idiomatic coding (for loop) or avoiding double code (getting first element and getting next element).

My advice would be to use iterators in a for loop, but this might be not that good in this case.




回答5:


Maybe we should write it as:

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
}


来源:https://stackoverflow.com/questions/15022085/smart-pointer-test-in-a-while-loop-use-the-comma-operator

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!