2

There is smart pointer class:

template <typename T>
class UniquePtr {
public:
    UniquePtr(T* obj)
        : obj(obj)
    {
    }
    UniquePtr(const UniquePtr& ptr) = delete;
    UniquePtr(UniquePtr&& ptr)
    {
        std::cout << "!! use of move !!" << std::endl;
        obj = std::move(ptr.obj);
        ptr.obj = nullptr;
    }

    UniquePtr& operator=(const UniquePtr& ptr) = delete;
    UniquePtr& operator=(const UniquePtr&& ptr) = delete;

    ~UniquePtr()
    {
        delete obj;
    }

private:
    T* obj;
};

class for test:

class Test {
public:
    Test()
    {
        std::cout << "Test is created" << std::endl;
    }
    Test(const Test& obj) = delete;
    Test(const Test&& obj) = delete;
    Test& operator=(const Test& obj) = delete;
    Test& operator=(const Test&& obj) = delete;
    virtual ~Test()
    {
        std::cout << "Test is destructed" << std::endl;
    }
};

and function:

void function(UniquePtr<Test>&& ptr)
{
    std::vector<UniquePtr<Test>> v;
    v.push_back(std::move(ptr));
}

If I pass Test class, everything is OK:

UniquePtr<Test> ptr(new Test);
function(std::move(ptr));

But if I pass derived from Test class, code isn't compiled:

class TestChild : public Test {
public:
    TestChild()
    {
        std::cout << "Test child is created" << std::endl;
    }
    TestChild(const TestChild& obj) = delete;
    TestChild(const TestChild&& obj) = delete;
    TestChild& operator=(const TestChild& obj) = delete;
    TestChild& operator=(const TestChild&& obj) = delete;
    virtual ~TestChild()
    {
        std::cout << "Test child is destructed" << std::endl;
    }
};
UniquePtr<TestChild> ptr(new TestChild);
function(std::move(ptr));
error: invalid initialization of reference of type ‘UniquePtr&&’ from
expression of type ‘std::remove_reference&>::type {aka UniquePtr}’
function(std::move(ptr)); ~~~~~~~~~^~~~~

How can I make UniquePtr<TestChild> convertible to UniquePtr<Test>&& With std::unique_ptr this code works.

3
  • 4
    (don't have time for a full answer) std::unique_ptr provides a constructor that makes the conversion possible : template< class U, class E > unique_ptr( unique_ptr<U, E>&& u ) noexcept; You need to replicate that functionality Commented Jun 28, 2017 at 15:39
  • This is odd: obj = std::move(ptr.obj);, obj being a pointer. Commented Jun 28, 2017 at 15:40
  • @YSC, yes, you're right, it's not necessary :) Commented Jun 28, 2017 at 15:46

1 Answer 1

2

Much like how std::unique_ptr handles it, you need to provide a templated constructor for your class that takes a UniquePtr of a different type (allowing SFINAE to deal with inheritance checking), which will then be used to initialize your UniquePtr's state.

template<typename U>
UniquePtr(UniquePtr<U> && other) {
    obj = other.obj;//Won't compile if U is not a subclass of T.
    other.obj = nullptr;
}
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks, It works. But, I make constructor like this: ` template <typename U> UniquePtr(UniquePtr<U>&& ptr) { obj = ptr.get(); ptr.reset(); } ` Because Unique_Ptr<U> has other type and obj becomes inaccessible
however, I found better solution, I added template <typename U> friend class UniquePtr;. It gives me access to private members

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.