-1

Please read updates for clarification.

Suppose there is a class Resource that handles acquisition and release of some resource.

Now I have my class

    class MyClass{
    public:
        MyClass(){};
        MyClass(MyClass&& other){
            ...
        }
    
    private:
        Resource r1;
        Resource r2;
    }

The problem is when the move constructor is called, the resources r1 and r2 are already acquired. But I don't need them if I'm going to move the resources from other object.

What am I getting wrong?

Update: Resource supports move and is not copiable.

Update 2: First there was some misunderstanding about the Resource class. I didn't post its implementation because I supposed it would be pretty regular one. The class acquires a resource on creation and releases on destruction). The class is movable. I think most resource handling classes are of that kind.

The real problem was that I tought I need to implement some sort of copy-and-swap. But the idiom seems to work well when you manage a resource yourself. If you use a ready RAII class for resources, then copy-and-swap will not work. Correct me if I'm wrong again.

So, with help of JohnFilleau's comment I came to the following code:

    class MyClass{
    public:
        MyClass(){};
        MyClass(MyClass&& other): r1(std::move(other.r1)), r2(std::move(other.r2)){};
    
    private:
        Resource r1;
        Resource r2;
    }
AlexVB
  • 217
  • 4
  • 11
  • You are totally wrong! Moving did not mean to move an object from one place into another, it means to take over ownership. As long your class contains the objects itself instead of an pointer or reference, you can't "move". Maybe your embedded object are able to "move", than you simply have to forward the incoming objects to the move-constructor of these embedded objects. – Klaus Dec 09 '21 at 14:57
  • I could swap r1 and r2 with other. Or not? What shall I do if r1 and r2 are not-copiable? – AlexVB Dec 09 '21 at 15:01
  • As Klaus mentioned, this is probably due to a misunderstanding of how move works in C++. To really tell you if there are any issues with re-acquiring already-acquired resources, we'd need to see your `Resource` class. – AndyG Dec 09 '21 at 15:01
  • Don't acquire real resources in your move constructor. Either construct a "dummy" `MyClass` with fake resources, and then `swap(*this, other)`, or directly assign `r1` and `r2` in your initializer list with `other.r1` and `other.r2`. – JohnFilleau Dec 09 '21 at 15:01
  • 3
    "What shall I do if r1 and r2 are not copyable?" it's generally been my experience that anything worth considering a resource is usually NOT copyable. It should have it's own move constructor. – JohnFilleau Dec 09 '21 at 15:03
  • "I could swap r1 and r2 with other. Or not? " How should we know? We have no idea what Resource is at all. You can swap what you want, the question is, what will be done in such a case? Full creation and destruction of the effected objects or only swapping two pointers somewhere... I vote to close as this ends up in an endless discussion as long nobody knows what is the underlying problem here... – Klaus Dec 09 '21 at 15:04
  • Any resource that needs to be managed like this benefits from having a null concept. That way I can have an "empty" `MyClass` which manages no resources and can be deconstructed without affecting anything real. – JohnFilleau Dec 09 '21 at 15:04
  • @JohnFilleau Thank you. Using initializer list will probably work. I just had an impression I need to implement some sort of copy-and-swap, but this seems unapplicable to the case whith noncopiable memeber variables. – AlexVB Dec 09 '21 at 15:11
  • Your example is currently missing the move assignment operator, copy constructor, copy assignment operator, and deconstructor. The presence of the move constructor implies the necessity of all five. Depending on the resource, your copy c'tor and assignment operator may need to be explicitly deleted. – JohnFilleau Dec 09 '21 at 15:21
  • @JohnFilleau You are right. I just wanted to focus on move constructor. I understand that MyClass have to be noncopiable as well. If you post your suggestion (about initialization) as an answer, I'll accept it. If you have better idea of how to implement a class that have for example two RAII-class file handlers, I would also appreciate hearing it. – AlexVB Dec 09 '21 at 15:25

1 Answers1

-3

Now the problem is when the move constructor is called, the resources r1 and r2 are already acquired.

No. r1 and r2 will be initialized at move ctor when you write so or specify =default. No resource will be accused before you initialize.

You need to think about why "move semantics" is semantics.

yumetodo
  • 1,147
  • 7
  • 19
  • 1
    Depending on the default constructor of `Resource`, `r1` and `r2` could very well be managing some resource once the body of the move constructor is entered. – JohnFilleau Dec 09 '21 at 15:07
  • @JohnFilleau Why a move constructor run default construction before? And even if this is the case, why it should start dealing with resources so late ( in the body of the move constructor ) if all can be done during initialization phase? – Klaus Dec 09 '21 at 15:09
  • @Klaus member variables are created before you enter constructor body. IMHO. – AlexVB Dec 09 '21 at 15:16
  • @Alex that's more than just your humble opinion. That's specified in the standard. – JohnFilleau Dec 09 '21 at 15:19
  • @Klaus I agree that resources should be initialized in the initializer list (when possible, which is usually is). As the question is written, though, there is no initializer list. – JohnFilleau Dec 09 '21 at 15:19
  • @AlexVB: "member variables are created before you enter constructor body." Exactly! That is why I wrote my comment above regarding default constructor and body of move constructor. All that makes no sense to me... :-) – Klaus Dec 09 '21 at 15:45
  • "member variables are created before you enter constructor body" Obviously, No. Before any ctor call, the object is not initialized. https://wandbox.org/permlink/EPFAtZQshihv0N4V – yumetodo Dec 17 '21 at 14:21