Комментирование `move constructor` и` move assignment operator` приводит к ошибке компиляции - PullRequest
0 голосов
/ 31 октября 2018

Я взял следующий код из Десять функций C ++ 11, которые должен использовать каждый разработчик C ++ . Я хочу видеть вывод с / без move constructor и move assignment operator. Оригинальный код хорошо компилируется. Но если я закомментирую реализацию двух методов, он не скомпилируется с ошибкой:

move-1.cpp: In instantiation of ‘Buffer<T>& Buffer<T>::operator=(const Buffer<T>&) [with T = int]’:
move-1.cpp:90:6:   required from here
move-1.cpp:40:17: error: no match for ‘operator=’ (operand types are ‘std::unique_ptr<int [], std::default_delete<int []> >’ and ‘int*’)
         _buffer = _size > 0 ? new T[_size] : nullptr;

Компилятор: gcc version 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04.4)

Вот код:

#include <cassert>
#include <iostream>
#include <memory>
#include <string>

template <typename T> class Buffer {
  std::string _name;
  size_t _size;
  std::unique_ptr<T[]> _buffer;

public:
  // default constructor
  Buffer() : _size(16), _buffer(new T[16]) {
    std::cout << "default constructor\n";
  }

  // constructor
  Buffer(const std::string &name, size_t size)
      : _name(name), _size(size), _buffer(new T[size]) {
    std::cout << "param constructor\n";
  }

  // copy constructor
  Buffer(const Buffer &copy)
      : _name(copy._name), _size(copy._size), _buffer(new T[copy._size]) {
    T *source = copy._buffer.get();
    T *dest = _buffer.get();
    std::copy(source, source + copy._size, dest);
    std::cout << "copy constructor\n";
  }

  // copy assignment operator
  Buffer &operator=(const Buffer &copy) {
    if (this != &copy) {
      _name = copy._name;

      if (_size != copy._size) {
        _buffer = nullptr;
        _size = copy._size;
        _buffer = _size > 0 ? new T[_size] : nullptr;
      }

      T *source = copy._buffer.get();
      T *dest = _buffer.get();
      std::copy(source, source + copy._size, dest);
      std::cout << "copy assignment\n";
    }

    return *this;
  }

  // move constructor
  Buffer(Buffer &&temp)
      : _name(std::move(temp._name)), _size(temp._size),
        _buffer(std::move(temp._buffer)) {
    temp._buffer = nullptr;
    temp._size = 0;
    std::cout << "move constructor\n";
  }

  // move assignment operator
  Buffer &operator=(Buffer &&temp) {
    assert(this != &temp); // assert if this is not a temporary

    _buffer = nullptr;
    _size = temp._size;
    _buffer = std::move(temp._buffer);

    _name = std::move(temp._name);

    temp._buffer = nullptr;
    temp._size = 0;
    std::cout << "move assignment\n";

    return *this;
  }
};

template <typename T> Buffer<T> getBuffer(const std::string &name) {
  Buffer<T> b(name, 128);
  return b;
}

int main() {
  Buffer<int> b1;
  Buffer<int> b2("buf2", 64);
  Buffer<int> b3 = b2;
  Buffer<int> b4 = getBuffer<int>("buf4");
  b1 = getBuffer<int>("buf5");
  return 0;
}

1 Ответ

0 голосов
/ 31 октября 2018

В main вызываются следующие конструкторы / операторы присваивания:

Buffer<int> b1;                          // default constructor
Buffer<int> b2("buf2", 64);              // constructor
Buffer<int> b3 = b2;                     // copy constructor
Buffer<int> b4 = getBuffer<int>("buf4"); // move constructor
b1 = getBuffer<int>("buf5");             // move assignment operator

Когда вы удаляете операции перемещения, это становится:

Buffer<int> b1;                          // default constructor
Buffer<int> b2("buf2", 64);              // constructor
Buffer<int> b3 = b2;                     // copy constructor
Buffer<int> b4 = getBuffer<int>("buf4"); // copy constructor
b1 = getBuffer<int>("buf5");             // copy assignment operator

Последняя строка (b1 = getBuffer<int>("buf5");) выявляет проблему в вашем операторе назначения копирования: вы не можете использовать operator=, чтобы назначить необработанный указатель на unique_ptr. Вместо этого используйте reset или создайте новый unique_ptr:

// copy assignment operator
Buffer &operator=(const Buffer &copy) {
  if (this != &copy) {
    _name = copy._name;

    if (_size != copy._size) {
      _buffer = nullptr;
      _size = copy._size;
      if (_size > 0) {
        _buffer.reset(new T[_size]);
      }
    }

    T *source = copy._buffer.get();
    T *dest = _buffer.get();
    std::copy(source, source + copy._size, dest);
    std::cout << "copy assignment\n";
  }

  return *this;
}

Чтобы поймать это, даже если ваши конструкторы перемещения включены, я бы добавил в main новый тест, который вынужден использовать оператор присваивания копии, например:

// ...
b1 = getBuffer<int>("buf5");             // move assignment operator
b2 = b3;                                 // copy assignment operator
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...