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