I'm writing a simple game engine in C++.
I'm very late to C++, because I've spent most of my free time with C, so the unique_ptr
, shared_ptr
and all of this ownership magic is hardly understandable for me.
I stumbled upon one thing that I can't understand at all. Let's have a following snippet:
#include <memory>
#include "vertexArray.hpp" // here VertexArray class is defined, it's implementation isn't important I think
class Mesh {
public:
Mesh()= default;
Mesh(std::unique_ptr<VertexArray>&& vertexArray) {
// this->vertexArray = vertexArray; <- this doesn't work
this->vertexArray = std::move(vertexArray); // Why is the move necessary?
}
private:
std::unique_ptr<VertexArray> vertexArray;
};
int main() {
auto vArray = std::make_unique<VertexArray>(/* vertex buffer, index buffer, etc */);
Mesh mesh = Mesh(std::move(vArray)); // <- I have to move the unique_ptr here, that I understand
}
I'm having a problem with this snippet, because I can't understand why the second std::move
is necessary inside the Mesh::Mesh(std::unique_ptr<VertexArray>&&)
.
From what I understand the assignment operator of std::unique_ptr
expect rvalue at the right side. Isn't the vertexArray
(which is type of std::unique_ptr<VertexArray>&&
) already a rvalue?
Also, the std::move(vertexArray)
isn't really clear to me, because in this example I guess the std::move
will return nothing else then std::unique_ptr<VertexArray>&&
, so isn't it returning exactly the same thing as vertexArray
already is?
From what I understand, it is, so why do I have to call the std::move(vertexArray)
where vertexArray
is already a rvalue, to then convert it to... a rvalue?
Types and value categories are two independent things in C++.
vertexArray
is an lvalue-expression as it's the name of variable, even its type is rvalue-reference. You have to use std::move
to convert it to rvalue-expression.
The following expressions are lvalue expressions:
- the name of a variable, ...
std::move(vertexArray)
is an xvalue-expression (rvalue-expression), as it's a function call whose return type is rvalue reference.
The following expressions are xvalue expressions:
- a function call or an overloaded operator expression, whose return type is rvalue reference to object, such as
std::move(x)
;