Home > database >  Why my unique_ptr realized by myself does not provide a call operator?
Why my unique_ptr realized by myself does not provide a call operator?

Time:03-13

First i realize unique_ptr by myself:

namespace mcj {
template <typename CallbackT>
class unique_ptr {
 public:
  unique_ptr(CallbackT* ptr = nullptr) : ptr_(ptr) {}

  template <
      typename CallbackT1,
      typename = typename std::enable_if<
          std::is_convertible<CallbackT1*, CallbackT*>::value>::type>
  unique_ptr(unique_ptr<CallbackT1>&& ptr) {
    ptr_ = ptr.release();
  }

  unique_ptr(unique_ptr<CallbackT>&& ptr) {
    if (ptr_) {
      delete ptr_;
      ptr_ = nullptr;
    }
    ptr_ = ptr.release();
  }

  template <
      typename CallbackT1,
      typename = typename std::enable_if<
          std::is_convertible<CallbackT1*, CallbackT*>::value>::type>
  unique_ptr<CallbackT>& operator=(unique_ptr<CallbackT1>&& ptr) {
    ptr_ = ptr.release();
  }

  unique_ptr<CallbackT>& operator=(unique_ptr<CallbackT>&& ptr) {
    if (ptr_) {
      delete ptr_;
      ptr_ = nullptr;
    }
    ptr_ = ptr.release();
    return *this;
  }

  unique_ptr(const unique_ptr<CallbackT>& other) = delete;
  unique_ptr<CallbackT>& operator=(const unique_ptr<CallbackT>& other) = delete;

  ~unique_ptr() {
    delete ptr_;
    ptr_ = nullptr;
  }

  CallbackT& operator*() { return *ptr_; }
  CallbackT* operator->() { return ptr_; }
  CallbackT* get() const { return ptr_; };

  CallbackT* release() {
    if (ptr_) {
      CallbackT* temp = ptr_;
      ptr_ = nullptr;
      return temp;
    }
    return ptr_;
  }

 private:
  CallbackT* ptr_;
};
}  // namespace mcj

namespace mcj {
template <typename CallbackT, typename ClosureT>
inline mcj::unique_ptr<CallbackT> make_unique(ClosureT&& closure) {
  return mcj::unique_ptr<CallbackT>(new CallbackT(std::forward<ClosureT>(closure)));
}

then i test my unique_ptr like these and successfully!

class A {
 public:
  A() {}

  A(A* ptr) {
    this->a = ptr->a;
    this->b = ptr->b;
  }

  A(const A& ptr) {
    this->a = ptr.a;
    this->b = ptr.b;
  }

  A(A&& ptr) {
    a = ptr.a;
    b = ptr.b;
  }

  void GetA() { std::cout << "a:" << a << std::endl; }
  int a = 0;
};
    auto s1 = std::make_unique<A>();
  s1->GetA();
  mcj::unique_ptr<A> a(new A());
  a->GetA();
  mcj::unique_ptr<A> b(std::move(a));
  b->GetA();
  mcj::unique_ptr<A> c;
  c = std::move(b);
  c->GetA();

above exapmles shows that my unique_ptr has overrided operator-> successfully!While when i want to try more complex class, it failed! Please look following code

namespace mcj {

class AppleCallback {
 public:
  virtual ~AppleCallback() = default;
  virtual void OnAppleComplete(int err) = 0;
}; 

namespace callback_impl {

template <typename CallbackT, typename ClosureT>
class ClosureCallback : public CallbackT {
 public:
  explicit ClosureCallback(ClosureT&& closure)
      : closure_(std::forward<ClosureT>(closure)) {}

 protected:
  typename std::remove_reference<ClosureT>::type closure_;
};

template <typename ClosureT>
class AppleCallbackImpl : public ClosureCallback<mcj::AppleCallback, ClosureT> {
 public:
  explicit AppleCallbackImpl(ClosureT&& closure)
      : ClosureCallback<AppleCallback, ClosureT>(
            std::forward<ClosureT>(closure)) {}
  void OnAppleComplete(int err) override {
    this->closure_(err);
  }
};

}  // namespace callback_impl
}  // namespace mcj

namespace mcj {
template <typename CallbackT,
          typename ClosureT,
          typename std::enable_if<
              std::is_same<CallbackT, AppleCallback>::value>::type* = nullptr>
mcj::unique_ptr<CallbackT> ToUniqueCallback(ClosureT&& closure) {
  return mcj::make_unique<callback_impl::AppleCallbackImpl<ClosureT>>(
      std::forward<ClosureT>(closure));
}
}  // namespace mcj

namespace mcj {
template <typename CallbackT>
class MoveOnlyCallback {
  using MyType = MoveOnlyCallback<CallbackT>;
  mcj::unique_ptr<CallbackT> callback_;

 public:
  template <typename ClosureT>
  MoveOnlyCallback(ClosureT&& closure)
      : callback_(
            ToUniqueCallback<CallbackT>(std::forward<ClosureT>(closure))) {
    std::cout << "move constructor\n" << std::endl;
  }
  MoveOnlyCallback(std::unique_ptr<CallbackT> callback)
      : callback_(std::move(callback)) {}
  MoveOnlyCallback() = default;
  MoveOnlyCallback(const MyType&) = delete;
  MoveOnlyCallback(MyType&&) noexcept = default;

  MyType& operator=(const MyType&) = delete;
  MyType& operator=(MyType&&) noexcept = default;
  CallbackT* operator->() const { return callback_.get(); }
  explicit operator bool() const noexcept { return callback_.operator bool(); }
  CallbackT* Get() const noexcept { return callback_.get(); };
  CallbackT* Release() noexcept { return callback_.release(); }
  mcj::unique_ptr<CallbackT> ReleaseUnique() noexcept {
    return std::move(callback_);
  }
};

class Apple : public Fruit {
 public:
  virtual ~Apple() = default;
  void Name() override { std::cout << "I am apple \n" << std::endl; }
  void Eat(MoveOnlyCallback<AppleCallback> callback) {
    callback->OnAppleComplete(0);
    // InvokeCallback(callback.Get(), 0);
  }
};

}  // namespace mcj

when i call function "Eat" of class "Apple" like this, it occurs error about operation-> of my unique_ptr, and if i replace my unique_ptr by std::unique_ptr, it is ok!

Apple* apple = new Apple();
  apple->Eat(ToUniqueCallback<AppleCallback>(
       [](int err) { std::cout << "eat callback" << std::endl; }));

here is error message!

/Users/chaojie.mo/Documents/test/src/callback_utils.h:138:5: error: type 'mcj::unique_ptrmcj::AppleCallback' does not provide a call operator this->closure_(err); ^~~~~~~~~~~~~~ /Users/chaojie.mo/Documents/test/src/callback_utils.h:134:12: note: in instantiation of member function 'mcj::callback_impl::AppleCallbackImplmcj::unique_ptr<mcj::AppleCallback>::OnAppleComplete' requested here explicit AppleCallbackImpl(ClosureT&& closure) ^ /Users/chaojie.mo/Documents/test/src/callback_utils.h:81:41: note: in instantiation of member function 'mcj::callback_impl::AppleCallbackImplmcj::unique_ptr<mcj::AppleCallback>::AppleCallbackImpl' requested here return mcj::unique_ptr(new CallbackT(std::forward(closure))); ^ /Users/chaojie.mo/Documents/test/src/callback_utils.h:153:15: note: in instantiation of function template specialization 'mcj::make_uniquemcj::callback_impl::AppleCallbackImpl<mcj::unique_ptr<mcj::AppleCallback>, mcj::unique_ptrmcj::AppleCallback>' requested here return mcj::make_unique<callback_impl::AppleCallbackImpl>( ^ /Users/chaojie.mo/Documents/test/src/callback_utils.h:168:13: note: in instantiation of function template specialization 'mcj::ToUniqueCallback<mcj::AppleCallback, mcj::unique_ptrmcj::AppleCallback, nullptr>' requested here ToUniqueCallback(std::forward(closure))) { ^ /Users/chaojie.mo/Documents/test/test/main.cpp:77:14: note: in instantiation of function template specialization 'mcj::MoveOnlyCallbackmcj::AppleCallback::MoveOnlyCallbackmcj::unique_ptr<mcj::AppleCallback>' requested here apple->Eat(ToUniqueCallback(

CodePudding user response:

MoveOnlyCallback has a constructor taking std::unique_ptr, but doesn't have one taking mcj::unique_ptr. Constructing from the latter ends up in the generic constructor template <typename ClosureT> MoveOnlyCallback(ClosureT&& closure). As a result you end up with double indirection, msj::unique_ptr<msj::unique_ptr<CallbackT>>

  • Related