3
votes

I have a class Whole that holds an object of a class Part via a unique_ptr. Since I do not provide a copy-constructor for Whole the copy-constructor is deleted, because of the unique_ptr member. Here is the code:

class Part {
};

class Whole {
public:
    Whole(std::unique_ptr<Part> part) : part(std::move(part)) {
    }
private:
    const std::unique_ptr<Part> part; //yields error later!
    //std::unique_ptr<Part> part; //ok!
};

I would like to create a Whole instance via a factory function called build()

Whole build() {
    auto part = std::unique_ptr<Part>{new Part{}};
    return Whole{std::move(part)};
}

which I want to use like this:

int main() {
    auto whole = build();
}

This works as long as the unique_ptr to the Part member of Whole is not declared const. As far as I understand this is due to the return value optimization which prevents the creation and copy of temporaries. However, if I declare Whole::part as const my compiler complains that the deleted copy-constructor is invoked. Why is it not possible to use the const declaration or is there a problem with this code anyway ?

I am using the GNU compiler version: (Ubuntu 4.8.4-2ubuntu1~14.04.1) 4.8.4

1
Copy elision is not mandatory. - Lingxi
Moving object modifies existing object. And by marking member const, you explicitely set it as not modifiable. - Revolver_Ocelot
Maybe you meant to use std::unique_ptr<const Part> part; ? - juanchopanza
There is an implicit move constructor. It's not to do with copy elision. - Simple

1 Answers

7
votes

const std::unique_ptr disallow move constructor of class Whole.

so auto whole = build(); is invalid. (even if the call would be elided, the call should be valid)

With C++17, we have guaranty copy elision which remove that restriction, making code correct.