I have a quick question regarding const-correctness for getters of vector of non-pointers.
Basically, I have this class with a non-const getter and a const getter for m_Vertices
:
class Mesh
{
public:
std::vector<Vertex>& GetVertices() { return m_Vertices; }
const std::vector<Vertex>& GetVertices() const { return m_Vertices; }
private:
std::vector<Vertex> m_Vertices;
}
The non-const getter makes sense; the getter is non-const, we return a non-const reference to a vector of non-const Vertex
instances.
The const getter in the other hand doesn't makes sense to me. I'm questioning the const-correctness and whether I should just return a copy of the vector. The problem I see is that we return a const reference to a vector of non-const Vertex
instances. So, the callee will have a const reference to m_Vertices
, but will still be able to modify the Vertex
instances, which feels wrong to me in terms of const-correctness.
In that case, should I simply return a copy of m_Vertices
?
First of all, understand that this is an opinion-based question. There are no right or wrong answers when you are designing a class regarding the usage of const.
However, that said, in this case your const declarations are reasonable. In particular your statement "the callee will have a const reference to m_Vertices, but will still be able to modify the Vertex instances" is not true -- because of the decisions that were made in the design of std::vector
regarding const-ness.
There are three main ways someone might want to modify the vector and its elements. The callee may want to add/delete items to/from the vector, may want to change the value of a field of the elements, or may want to replace one of the elements. A reference to a const vector will make all three of those actions errors:
#include <iostream>
#include <vector>
#include <span>
struct point {
double x;
double y;
};
class vertices {
std::vector<point> points_;
public:
vertices(std::span<const point> pts) :
points_{pts.begin(), pts.end()}
{}
const std::vector<point>& get() const {
return points_;
}
std::vector<point>& get() {
return points_;
}
};
int main()
{
vertices verts({{ {1.0,2.0}, {3.0,4.0}, {5.0,6.0} }});
const auto& const_verts = verts;
verts.get().push_back({ 7.0,8.0 }); // <= yes.
//const_verts.get().push_back({ 7.0,8.0 }); <= no.
verts.get().front().x += 1; // <= yes.
//const_verts.front().x += 1; // <= also no.
verts.get()[2] = { 0.0,0.0 }; // <= yes.
//const_verts.get()[2] = { 0.0,0.0 }; <= no.
}