One Megabyte Memcpy

A profiler shows a 1 MB memcpy at line B, which the author believed was a move.

class Buffer {
public:
    explicit Buffer(std::size_t n) : n_(n), data_(new char[n]) {}
    ~Buffer() { delete[] data_; }
    Buffer(const Buffer& o) : n_(o.n_), data_(new char[o.n_]) {
        std::memcpy(data_, o.data_, n_);
    }
private:
    std::size_t n_;
    char* data_;
};

std::vector<Buffer> v;
v.reserve(4);
Buffer b(1 << 20);
v.push_back(std::move(b));   // B

Why does line B copy?

A

std::move(b) produces a prvalue, and prvalues prefer a const& parameter over an rvalue reference.

B

Buffer has a user-declared destructor and a user-declared copy constructor, so no move constructor is implicitly declared; the element is therefore constructed by the copy constructor.

C

std::vector uses std::move_if_noexcept, and Buffer's move constructor is not marked noexcept, so the vector chooses the copy.

D

reserve(4) reserves capacity but not size, so push_back reallocated and copied the existing elements.