简体   繁体   中英

Can you design a constructor to allow `Class c(std::move(another_class))` when the class has a member of type const std::unique_ptr?

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 (ie 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:

  1. Remove const qualifier:

    std::unique_ptr<int> ptr_ ;

    The problem is that this reads as: "ptr_ member might be modified when calling public methods"

  2. 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)?

  • Constructing the class instance from another class instance, possibly destroying another instance in the process (ie c(std::move(d) );
  • Allowing the class to have a member of type const unique_ptr

This intersection of desires is inherently contradictory.

Moving is a modifying operation. If the object is const , you cannot move from it.

The entire purpose of unique_ptr is that there is one instance in the program which uniquely owns (and will destroy) the object it points to. Therefore, it cannot be copied, because a copy is a non-modifying operation. If it could be copied, then two objects would try to own the same object.

You cannot copy from a unique_ptr . You cannot move from a const object of any kind. Therefore, if your object has a const unique_ptr , it cannot get a pointer from some other instance of that object.

By declaring a member to be a const unique_ptr<T> , you are also declaring that the object can be neither copied nor moved. Those are the consequences of your code choices.

So you're going to have to decide what is more important: the member being const or the ability to copy/move from this object.

Broadly speaking, const members create more problems than they usually solve. If the member is private, then that is usually good enough protection; users with direct access to the class should be able to know what each such function should and should not modify. And if they make a mistake, the code in which that mistake can appear is pretty limited.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM