【问题标题】:Problems with implementation of unique_ptr's move constructorunique_ptr 的移动构造函数的实现问题
【发布时间】:2019-05-17 00:47:57
【问题描述】:

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

  1. 当我将移动构造函数标记为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?

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

【问题讨论】:

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


    【解决方案1】:

    1) 默认的移动构造函数不知道你的类的语义。所以它移动了指针rhs,但它不会重置另一个指针,它也会在另一个析构函数中被删除。

    2) *rhs 调用 operator* 并返回一个临时/右值 T*,一个内部指针的副本,与通常的 operator* 不一致,后者应该返回 T&amp; 或 @987654327 @。

    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;}
    

    等等。

    【讨论】:

    • 构造函数不应该删除它的指针,因为那个指针没有指向任何有意义的东西。
    • 哦,是的,对不起,搞砸了分配...也将其移至初始化列表。非常感谢您的检查!
    【解决方案2】:

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-05-25
      • 2017-09-24
      • 1970-01-01
      • 1970-01-01
      • 2013-01-03
      • 1970-01-01
      • 2013-03-27
      • 1970-01-01
      相关资源
      最近更新 更多