In the following example we have a class Class
that contains a Bridge
object that takes care of all the memory handling for us (rule of three).
class Base {
public:
Base() {};
virtual Base* clone() const = 0;
virtual ~Base() {};
};
class Derived : public Base {
public:
Derived() {};
virtual Base* clone() const {
return new Derived(*this);
}
virtual ~Derived() {}
};
class Bridge {
public:
Bridge(const Bridge& bridge_) {
base = bridge_.base->clone();
}
Bridge(const Base& base_) {
base = base_.clone();
}
~Bridge() { delete base; }
Bridge& operator=(const Bridge& assignFrom) {
if(this != &assignFrom) {
delete base;
base = assignFrom.base->clone();
}
return *this;
}
private:
Base *base;
};
class Class {
public:
Class(const Bridge& bridge_) : bridge(bridge_) {};
private:
Bridge bridge;
};
int main()
{
Derived derived;
Class c(derived);
Class c1(c);
}
Now, I have just learned about smart pointers and was trying to recreate the above example using unique_ptr
. To my understanding, we basically don't need to implement the rule of 3 ourselves as the smart pointer contains it already. To test this, I made the following example:
class BaseSMRT {
public:
BaseSMRT() {};
virtual std::unique_ptr<BaseSMRT> clone() const = 0;
virtual ~BaseSMRT() {};
};
class DerivedSMRT : public BaseSMRT {
public:
DerivedSMRT() {};
virtual std::unique_ptr<BaseSMRT> clone() const {
return std::make_unique<DerivedSMRT>(*this);
}
virtual ~DerivedSMRT() {}
};
class ClassSMRT {
public:
ClassSMRT(const BaseSMRT& base) {
ptr = base.clone();
};
private:
std::unique_ptr<BaseSMRT> ptr;
};
int main()
{
DerivedSMRT derivedSMRT;
ClassSMRT cSMRT(derivedSMRT);
ClassSMRT cSMRT2(cSMRT); // error: Call to implicitly-deleted copy constructor of 'ClassSMRT'
}
As you can see in the above example, initialising cSMRT2
with cSMRT
through the copy constructor doesn't work and gives me the above error.
I don't get this: Why is it that I can call Class
's default copy constructor like this, Class c1(c);
, but not call ClassSMRT
's default copy constructor, ClassSMRT cSMRT2(cSMRT);
?
This suggests that the rule of three isn't already implemented for us when we are using unique_ptr
.
std::unique_ptr
is non-copyable. It doesn't have a copy constructor that makes a copy of the object that is held byunique_ptr
. – Rammerstd::unique_ptr
? I would still have to implement it myself? In that case, I can't see what the usage is ofstd::unique_ptr
is in this particular case – Usurpunique_ptr
it is a rule of 5, but copy operations are deleted. If you want to copy an object, you should do it yourself. It would be semantically wrong for a smart pointer to make such a copy - after all, it is just a pointer. – Rammerunique_ptr
not as a pointer, but as a unique object – it can't be copied, it can only be moved. – Kamikamikazestd::move
in the clone? – UsurpClassSMRT
. You need to define what copying an object that has a non-copyable member means in your particular case. – Kamikamikaze