Consider the following class Buffer
, which contains an std::vector
object:
#include <vector>
#include <cstddef>
class Buffer {
std::vector<std::byte> buf_;
protected:
Buffer(std::byte val): buf_(1024, val) {}
};
Now, consider the function make_zeroed_buffer()
below. The class BufferBuilder
is a local class that publicly derives from Buffer
. Its purpose is to create Buffer
objects.
Buffer make_zeroed_buffer() {
struct BufferBuilder: Buffer {
BufferBuilder(): Buffer(std::byte{0}) {}
};
BufferBuilder buffer;
// ...
return buffer;
}
If no copy elision takes place, is the buffer
object above guaranteed to be moved from?
My reasoning is the following:
- The expression
buffer
in thereturn
statement is an lvalue. Since it is a local object that is not going to be used anymore, the compiler casts it into an rvalue. - The
buffer
object is of typeBufferBuilder
.Buffer
is a public base class ofBufferBuilder
, so thisBufferBuilder
object is implicitly converted into aBuffer
object. - This conversion, in turn, implies an implicit reference-to-derived to a reference-to-base conversion (i.e., a reference to
BufferBuilder
to a reference toBuffer
). That reference toBufferBuilder
is an rvalue reference (see 1.), which turns into an rvalue reference toBuffer
. - The rvalue reference to
Buffer
matchesBuffer
's move constructor, which is used to construct theBuffer
object thatmake_zeroed_buffer()
returns by value. As a result, the return value is constructed by moving from theBuffer
part of the objectbuffer
.