Комментирование `move constructor` и`move assignment operator` приводит к ошибке компиляции
Я взял следующий код из десяти функций 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 ©)
: _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 ©) {
if (this != ©) {
_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 ответ
В 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 ©) {
if (this != ©) {
_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