Const-correctness with getters of vector of non-pointers

73 Views Asked by At

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?

1

There are 1 best solutions below

0
jwezorek On BEST ANSWER

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.
}