Проблемы с реализацией конструктора перемещения unique_ptr - PullRequest
0 голосов
/ 16 декабря 2018

Я пытаюсь написать реализацию 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?

Пожалуйста, откажитесь от любых других ошибок реализации, которые не относятся к описанным проблемам.Работа продолжается.

Ответы [ 2 ]

0 голосов
/ 16 декабря 2018

Ты слишком стараешься.Вам не нужно проходить через внешний интерфейс.Просто присвойте значения:

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

Кроме того, operator*() должно возвращать T&, а не T*.

0 голосов
/ 16 декабря 2018

1) Конструктор перемещения по умолчанию не знает о семантике вашего класса.Поэтому он перемещает указатель rhs, но не сбрасывает другой указатель, который также будет удален в другом деструкторе.

2) *rhs вызывает operator* и возвращает временное значение / r.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;}

И так далее.

...