Below is the simplified version of a class that I am trying to design
class Class {
public:
Class(std::unique_ptr<int>&& ptr): ptr_(std::move(ptr)) {}
private:
// works only if I change to std::shared_ptr or remove const qualifier
const std::unique_ptr<int> ptr_;
};
int main() {
std::unique_ptr<int> ptr = std::make_unique<int>(1);
Class c(std::move(ptr)); // Compiles
// I need to construct a new instance d, but c is not needed anymore,
// anything c owns can be nullified.
Class d(std::move(c)); // Does not compile
return 0;
}
I can not construct an instance d from the instance c due to the following error message:
Copy constructor of 'Class' is implicitly deleted because field 'ptr_' has a deleted copy constructor
However, if I change the ptr_ member to be of type const std::shared_ptr<int>, then everything works.
Is there a way to have a single constructor for the Class, which would support:
- Constructing the class instance directly providing the arguments it needs
- Constructing the class instance from another class instance, possibly destroying another instance in the process (i.e. c(std::move(d));
- Allowing the class to have a member of type
const unique_ptr
?
EDIT: constructing an instance d using std::move(c) also doesn't work:
class.cc:17:23: error: use of deleted function ‘Class::Class(Class&&)’ 17 | Class d(std::move(c)); | ^ class.cc:5:7: note: ‘Class::Class(Class&&)’ is implicitly deleted because the default definition would be ill-formed:
So far two solutions work for me, neither are perfect from readability point of view:
Remove
constqualifier:std::unique_ptr<int> ptr_;The problem is that this reads as: "ptr_ member might be modified when calling public methods"
Change to shared pointer:
const std::shared_ptr<int> ptr_;The problem is that this reads as: "we have multiple pointers pointing to the same data"
Any way to improve the design which wouldn't have the problems outlined in (1) and (2)?
Is there a way to have a single constructor for the Class, which would support:No.cany more afterwards is to passstd::move(c)instead ofc, which will cause the move constructor to be used, which is already defined implicitly:Class d(std::move(c));.constas well. Making the pointerconstmeans that you intent it to be impossible for it to relinquish ownership. If you want to be able to transfer ownership, then it must not beconst.