Search code examples
c++unique-ptrmove-semantics

Function signature for potentially failed unique_ptr move?


Say I am writing a enqueue() function that takes in a unique_ptr, but I only want to claim its ownership when enqueue returns success. If the queue is full I want to leave the unique_ptr intact (user can retry with the same item later)

bool enqueue(std::unique_ptr&& item){
  if(!vector.full()){
    vector.emplace(std::move(item));
    return true;
  }
  return false;
}
// usage
auto item_ptr = make_unique<>();
while(!enqueue(std::move(item_ptr))){
// item_ptr is not moved
}

I can also define the function to take a lvalue reference instead

bool enqueue(std::unique_ptr& item)
while(!enqueue(item_ptr)){
// item_ptr is not moved
}

I am not sure which one to pick, they all seemed a little anti-patterned since usually std::move indicates the deletion of a unique_ptr (most of the time, I work with function that takes unique_ptr by value), maybe there's a better solution?


Solution

  • You could return a unique_ptr from your function. If it failed return the original. If it succeeded return an empty unique_ptr.

    Then you could call it like:

    #include <iostream>
    #include <memory>
    #include <vector>
    
    int counter = 10;
    
    template <typename T> std::unique_ptr<T> enqueue(std::unique_ptr<T> p) {
      if (--counter == 0)
        return std::unique_ptr<T>();
      return p;
    }
    
    int main() {
      auto item_ptr = std::make_unique<int>(8);
      while (item_ptr = enqueue(std::move(item_ptr))) {
        std::cout << "looping\n";
      }
      std::cout << "moved\n";
      return 0;
    }
    

    Actually, I'd better go try this out. Yeah my first idea had a bug. Ripping out that ! from the while loop. Always test. :-)