0

If I have a class with getters of return type both const and non-const, how can I use the non-const one?

The class (MeshManipulator.h):

namespace vortex::meshSculptEngine
{
    class MeshManipulator
    {
    public:
        ...
        topologyMesh::Mesh* getMesh();
        const topologyMesh::Mesh* getMesh() const;
        ...
    };
}

The code where I want to use the Mesh (SimpleMeshCorrector.cpp):

void SimpleMeshCorrector::smoothBoundaryLoops(float distance)
{
    if (!_boundaryLoops.empty()) {
        Mesh* mesh = getEngine()->getManipulator()->getMesh();
        ...
    }
}

I get the following error:

A value of type "const vortex::topologyMesh::Mesh*" cannot be used to initialize an entity of type "vortex::topologyMesh::Mesh*"

I can use const_cast but I just don't feel that this is the correct way to solve this problem.

wohlstad
  • 12,661
  • 10
  • 26
  • 39
Zoltán Orosz
  • 303
  • 1
  • 8
  • 1
    Do not use const_cast. What does the "getManipulator" return? Provide minimal, reproducible example https://stackoverflow.com/help/minimal-reproducible-example – bielu000 Feb 02 '23 at 09:29
  • 4
    Probably either `getEngine()` or `getManipulator()` return a pointer to `const`. Either change that (and the non-const version will be used) or do the `const_cast` (which is the wrong way to solve it). – Friedrich Feb 02 '23 at 09:30
  • 1
    @bielu000 It returns a const MeshManipulator* object – Zoltán Orosz Feb 02 '23 at 09:30
  • 4
    And that's the problem. You cannot call a non-const method on a const object. – Friedrich Feb 02 '23 at 09:31
  • 2
    Then you have your answer. MeshManiupulator* is a pointer to const object, then when you call getMesh, const overload will be used – bielu000 Feb 02 '23 at 09:31
  • @Friedrich So I should change the MeshManipulator getter to return a pointer to non-const object? And what if I am using an API and can't change this? I am just curious – Zoltán Orosz Feb 02 '23 at 09:33
  • 1
    Either you accept what the API gives you and that you should not change the `Mesh` object (there's probably a reason for it) or you `const_cast` at your own risk. Depending on what you want to do, you might also copy the `Mesh` object and manipulate your copy. – Friedrich Feb 02 '23 at 09:37
  • Okay, thank you guys for your time, it helps me a lot! Can you post it as an answer to accept it as a solution? – Zoltán Orosz Feb 02 '23 at 09:40
  • Do all your `getX` methods have both const and non-const versions? I mean `getEngine()` could return non-const engine, and so on... – Quimby Feb 02 '23 at 09:45
  • @Quimby No, only the MeshManipulator class has const and non-const getters for Mesh object, all the others have only const getters. – Zoltán Orosz Feb 02 '23 at 09:49
  • 2
    I find this convention very clear: `get()` (const) and `get_mutable()` (by reference or non-const pointer). – no more sigsegv Feb 02 '23 at 10:02
  • @nomoresigsegv Sorry, can you explain it a little bit more? I just don't really understand what do you mean about this – Zoltán Orosz Feb 02 '23 at 10:08
  • @nomoresigsegv I think I get it – Zoltán Orosz Feb 02 '23 at 10:16
  • 3
    What @nomoresigsegv meant is that - instead of having a const and a non-const method of the same name - they should have different names, e.g. `get() const` and `get_mutable()` (non-const). This makes constness explicit. – Friedrich Feb 02 '23 at 10:16
  • @Friedrich thank you for your help, now it's clear! After this problem I can really appreciate the value of this convention – Zoltán Orosz Feb 02 '23 at 10:19

1 Answers1

2

Root cause is (as clarified in comments) that getManipulator() returns a const MeshManipulator*. On a const object, only methods declared const can be called. Thus, the const getter is always called and never the non-const version.

Depending on the context, there are three ways to go on:

  • Use (or write) a method that returns a mutable MeshManipulator*.
  • Copy the const Mesh* to a local, mutable object.
  • Use const_cast<Mesh*> to be able to mutate the object in place. This, however, defeats the purpose of constness. What's more, if the object pointed to was declared const this will result in undefined behavior. So use with care.
Friedrich
  • 2,011
  • 2
  • 17
  • 19
  • No, the third is not close to acceptable. It is inviting UB to come screaming at you. – Passer By Feb 02 '23 at 11:14
  • @PasserBy I agree it should not be done unless you know what you're doing (same goes for my first suggestion, btw). What do you suggest? How can I improve this answer? – Friedrich Feb 02 '23 at 11:59
  • The first is fine and has plenty of legitimate use cases, what's your objection to it? `const_cast` is not. Mutating a `const` declared object is UB. – Passer By Feb 02 '23 at 12:40
  • @PasserBy I edited my post to address the danger of UB. Please let me know if there are further issues. My objection to the first one is that there has to be a reason for declaring anything `const`. Throwing it away because it's inconvenient may cause side effects. So you have to do your homework before doing it. Same as with `const_cast`. – Friedrich Feb 02 '23 at 13:00