与unique_ptr的move构造函数的实现有关的问题

时间:2018-12-16 11:59:07

标签: c++ move-semantics unique-ptr move-constructor

我正在尝试编写一个unique_ptr实现。我正在努力编写一个move构造函数。这是我的问题:

  1. 当我将move构造函数标记为default时,我的资源被删除两次,当我移动时分配一个指针(下面的auto foo2 = std::move(foo);)-为什么?
  2. 当我尝试在移动构造函数中分配像*rhs = nullptr这样的基础指针时(请参见下面的实现),编译器会说*rhs是一个右值,我无法为其分配任何内容。
  3. 最后,rhs.m_ptr = nullptr有效。为什么*rhs = nullptr不起作用,为什么它起作用?

我的代码:

#include <iostream>

namespace my
{
template <class T>
class unique_ptr
{
public:
    unique_ptr()
    {
        m_ptr = new T;
    }
    unique_ptr(const unique_ptr&) = delete;
    // move constructor
    unique_ptr(unique_ptr&& rhs)  // = default deletes m_ptr twice
    {
        m_ptr = *rhs;
        rhs.m_ptr = nullptr;  // *rhs = nullptr doesn't work (*rhs is an rvalue)
    }
    ~unique_ptr()
    {
        delete m_ptr;
    }
    T* operator->()
    {
        return m_ptr;
    }
    T* operator*()
    {
        return m_ptr;
    }
    unique_ptr& operator=(const unique_ptr&) = delete;
    // no move assignment yet
private:
    T* m_ptr;
};

}  // namespace my

struct Foo
{
    Foo()
    {
        std::cout << "Foo" << std::endl;
    }
    ~Foo()
    {
        std::cout << "~Foo" << std::endl;
    }
    void printHello()
    {
        std::cout << "Hello" << std::endl;
    }
};

int main()
{
    my::unique_ptr<Foo> foo;
    foo->printHello();

    auto foo2 = std::move(foo);

    return 0;
}

另一方面,显然我可以将不带任何模板参数的unique_ptr传递给unique_ptr类模板内的方法。编译器是否只是假设它是T?

请丢弃与所描述问题无关的任何其他实现错误。正在进行中。

2 个答案:

答案 0 :(得分:6)

1)默认的move构造函数不了解您的类的语义。因此它会移动指针rhs,但不会重置另一个指针,另一个指针也会在另一个析构函数中被删除。

2)*rhs调用operator*并返回临时/右值T*(内部指针的副本),并且与通常应返回的operator*不一致T&const T&

3)参见2.您正在返回一个临时对象。

所以最后,您应该拥有什么:

unique_ptr(unique_ptr&& rhs)  // = default deletes m_ptr twice
: m_ptr(rhs.m_ptr)
{
    rhs.m_ptr = nullptr;  // *rhs = nullptr doesn't work (*rhs is an rvalue)
}

T& operator*() {return *m_ptr;}
const T& operator*() const {return *m_ptr;}

以此类推。

答案 1 :(得分:2)

您太努力了。您不必通过外部接口。只需分配值即可:

m_ptr = rhs.m_ptr;
rhs.m_ptr = nullptr;

此外,operator*()应该返回T&,而不是T*