Search code examples
c++classpointersconstructor

Transfer the ownership of a already-defined std::unique_ptr to the member of a class object


I am trying to transfer the ownership of a already-defined std::unique_ptr to the member of a class object:

#include <iostream>
#include "memory"


// base class
class base
{
public:
    void setVal(int val)
    {
        m_val = val;
    }

    int getVal()
    {
        std::cout << "base val = " <<m_val<<std::endl;
        return m_val;
    }

private:
    int m_val = 0;
};

// derived class
class derived1: public base
{
private:
};

// derived class
class derived2: public base
{
public:

private:
};


class user
{
public:

    user(std::unique_ptr<base> d)
    {
//        m_class = static_cast<std::unique_ptr<base>>(d.get());
//        m_class = std::make_unique<base>();
        m_class = std::move(d);
    }
    user(std::unique_ptr<derived1> d)
    {
//        m_class = static_cast<std::unique_ptr<derived1>>(d.get());
//        m_class = std::make_unique<derived2>();
        m_class = std::move(d);

    }
    user(std::unique_ptr<derived2> d)
    {
//        m_class = static_cast<std::unique_ptr<derived2>>(d.get());
//        m_class = std::make_unique<derived2>();
        m_class = std::move(d);
    }

    void setVal(int val)
    {
        m_class->setVal(val);
    }

    int getVal()
    {
        return m_class->getVal();
    }

private:
    std::unique_ptr<base> m_class;

};

int main()
{
    std::unique_ptr<base> b = std::make_unique<base>();
    std::unique_ptr<base> d1 = std::make_unique<derived1>();
    std::unique_ptr<base> d2 = std::make_unique<derived2>();

    user ud1(std::move(d1));
    user ud2(std::move(d2));

    ud2.setVal(90);
    ud1.setVal(10);

    ud2.getVal();
    ud1.getVal();

    return 0;
}

It seems I std::moved the pointer twice; first time being passing the std::unique_ptr d1 and d2 to the constructor of user object; second time being std::move the d1 or d2 into member variable m_class.

It does not feel intuitive to std::move the pointer twice to eventually transfer the ownership of d1 and d2 to m_class. Am I doing this right, or there is a right/better way to do it? Thanks!!


Solution

  • Am I doing this right, or there is a right/better way to do it?

    It is correct to move it twice, since you are transferring the value between three different variables.

    It's also not a problem. std::move is a compile-time cast. Calling it twice has no performance implications.

    However...

    You should be using member initializer lists.

    user(std::unique_ptr<base> d)
        : m_class{ std::move(d) }
    {
    }
    

    And these constructors are superfluous. Delete them. You don't need to account for every possible derived type, they can all implicitly convert to std::unique_ptr<base>.

        user(std::unique_ptr<derived1> d)
        {
    //        m_class = static_cast<std::unique_ptr<derived1>>(d.get());
    //        m_class = std::make_unique<derived2>();
            m_class = std::move(d);
    
        }
        user(std::unique_ptr<derived2> d)
        {
    //        m_class = static_cast<std::unique_ptr<derived2>>(d.get());
    //        m_class = std::make_unique<derived2>();
            m_class = std::move(d);
        }