0

Consider the following code:

#include <memory>

class Object
{
public:
    Object(int* _i) : i(std::unique_ptr<int>(_i)) {}
    Object(Object&& other) : i(std::move(other.i)) {}
private:
    std::unique_ptr<int> i;
};

class Holder
{
public:
    Holder(Object&& _obj) : obj(std::make_unique<Object>(_obj)) {}
private:
    std::unique_ptr<Object> obj;
};

int main()
{
    Holder h(Object(new int(42)));

    return 0;
}

The compiler complains about copies of an Object instance being made, which would obviously be illegal since Object has a unique_ptr member. Does that error occur because I pass my parameter by-value? Shouldn't the signature of my constructor of Holder force a call by-reference?

What I understand even less is that after changing the constructor of my Holder class to

Holder(Object&& _obj) : obj(std::make_unique<Object>(std::move(_obj))) {}

the code compiles just fine. This does not make any sense to me, since if there was a copy made while passing the Object into the constructor of Holder changing anything within the constructor shouldn't resolve this.

  • 1
    Without adding `std::move`, the copy was made in `make_unique()` call - not in `Holder` constructor. – Eugene Jan 06 '23 at 05:26
  • @Eugene Well that's weird considering `make_unique` has the following signature: `inline std::unique_ptr std::make_unique(Object &&__args)`. Why would it change its parameter to an lvalue? – TheBeautifulOrc Jan 06 '23 at 05:35
  • 3
    Because `std::make_unique` is a template, in this signature, `Object &&__args` is a forwarding reference, not rvalue reference. And your actual argument `_obj` w/o std::move() is lvalue. The function needs to construct `Object` from your argument, and because the argument is lvalue, it is not allowed to move - it must copy. – Eugene Jan 06 '23 at 05:44

0 Answers0