I am writing code that passes a std::unique_ptr through a few layers that look bad, but I don't have a choice but pass it all along for now.
The problem is that I am getting an error when I try to pass the std::unique_ptr to a constructor of the Provider class. At the point where Child::function1() is called, Child has been initialized/constructed with parameters of Impl& and std::unique_ptr<Retriever> from somewhere else.
Could someone please tell me why I'm getting this error, and how to get this work? I wonder if it's because of the inheritance happening, but I can't figure it out what else to do besides moving to get this work... (apart from something like not to pass this ptr through all these classes that seem to look similar with the same constructors... lol)
// child.cpp
Child::Child(Impl& child_impl, std::unique_ptr<Retriever> child_retriever_up)
: Parent(child_impl, std::move(child_retriever_up))
{}
T::Y Child::function1() const
{
**Provider provider(d_impl, d_retriever_up);**
// these d_impl and d_retriever are in Parent class.
...
return Y;
}
// child.h
class Child : public Parent {
public:
// creators
explicit Child(Impl& child_impl, std::unique_ptr<Retriever> child_retriever_up);
~Child() override = default;
// accessors
T::Y Child::function1() const;
private:
Child(const Child&) = delete;
Child& operator=(const Child&) = delete;
// parent.cpp
Parent::Parent(Impl& impl, std::unique_ptr<Retriever> retriever_up)
: d_impl(impl), d_retriever_up(std::move(retriever_up))
{}
// parent.h
class Parent {
public:
// creators
explicit Parent(Impl& impl, std::unique_ptr<Retriever> retriever_up);
virtual ~Parent() = default;
// copy constructor
Parent(const Parent& parent)
: d_context(parent.d_impl)
, d_retriever_up(std::move(*parent.d_retriever_up))
{
}
// data
Impl& d_impl;
std::unique_ptr<Retriever> d_retriever_up;
private:
//Parent(const Parent&) = delete;
Parent& operator=(const Parent&) = delete;
// provider.cpp
Provider::Provider(Impl& impl, std::unique_ptr<Retriever> retriever_up)
: d_impl(impl)
, d_retriever(std::move(retriever_up))
{}
// provider.h
class Provider {
public:
Provider(Impl& context, std::unique_ptr<Retriever> retriever_up);
//copy contstructor
Provider(const Provider& provider)
: d_impl(provider.d_impl)
, d_retriever(std::move(*provider.d_retriever))
{
}
private:
Impl& d_impl;
std::unique_ptr<Retriever> d_retriever;
}
In
Child::function1(), you are passingd_retriever_upby value to theProviderconstructor. That requires making a copy ofd_retriever_up, which is impossible as it is aunique_ptrthat hasdelete'd its copy constructor, hence the error.You need to use
std::move()to moved_retriever_upintoProvider. You claim to be doing that, but you are not, at least not everywhere it is needed. Moving the caller'sunique_ptrinto theProviderconstructor'sretriever_upparameter is a separate operation than moving theretriever_upparameter into theProvider'sd_retrieverclass member.However, after you fix that, you will run into another problem.
Child::function1()is marked asconst, which makes access tod_retriever_upbeconstin that context, sofunction1()can't modifyd_retriever_up, including moves (since moving aunique_ptrsets its held pointer tonullptr).So, to make the code work, you need to drop the
constand addstd::move():That being said, moving
d_retriever_upis questionable in your design. You might need to consider usingstd::shared_ptrinstead.