mercredi 31 octobre 2018

Why doesn't my code compile if I comment out `move constructor` and `move assignment operator`?

I grabbed the following code from Ten C++11 Features Every C++ Developer Should Use. I want to see the output with / without move constructor and move assignment operator. The original code compiles well. But if I comment out implementation of the two methods, it fails to compile with error:

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;

Compiler: gcc version 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04.4)

Here is the code:

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

Aucun commentaire:

Enregistrer un commentaire