0

Let's say we have a class X that holds a pointer to an object of class Y. X never changes Y in any way, but other objects which might want to change Y can ask X for a pointer to Y. We want class X to be able to hold both const and variable objects. If we write something like this:

class Y;

class X {
public:
  const Y* getY();
private:
  const Y* y;
};

then we could never alter Y when getting it from X, even when the original "Y object" is not const.

An example where this would be useful is a linked list that holds both const and variable objects.

How would one go about implementing this?

7
  • Since you know the Y instance is mutable (guaranteed by forces above your head) return a non-const Y * and const_cast away the const in the getter. C++ always gives you the opportunity to do something stupid when there's a chance that it might not be stupid under controlled circumstances. 's why we still have widely reviled stuff like goto. Commented Oct 25, 2022 at 23:25
  • But remember that you have to be absolutely sure the sucker's mutable, so storing mutable and non-mutable data in the same container... That's stupid. But you could be able to get around it safely with the right abstraction. Commented Oct 25, 2022 at 23:28
  • So if I wanted class X to be able to hold both mutable and const objects, that would not be very smart then? Commented Oct 25, 2022 at 23:29
  • @user4581301 • Our goto has been castrated, since you can't do void foo() { goto yonder; } void bar() { yonder: cout << "We're here!\n"; } We've got structured goto, that's been tamed, constrained, and detained, rather than proper yeehaw goto that can rampage hither-and-yon. Assembly language programming, for the win! Commented Oct 25, 2022 at 23:29
  • 1
    @m_ognjen So if I wanted class X to be able to hold both mutable and const objects... If you have no way to guarantee that the Y is mutable, casting away const is not a good solution. But if you have a wrapper around it that can tell you if it's mutable or not you have the ability to say "Oh hell no!" if someone asks for a non-const pointer. Saying "No" may or may not be viable in your use case, but perhaps you can move the abstraction elsewhere. Commented Oct 25, 2022 at 23:53

1 Answer 1

2

You can think about the analogous situation of std::unique_ptr: one that holds a pointer to a mutable Y is std::unique_ptr<Y>, while one that holds a pointer to a const Y is std::unique_ptr<const Y>.

X can similarly be made into a template:

class Y;

template <class T>
class X {
public:
    T* getY();
private:
    T* p;
};

Here, X<Y> can hold a Y*, and X<const Y> can hold a const Y*. You may also want to make X<Y> implicitly convertible to X<const Y> by providing an appropriate constructor, so that any function that has a parameter of type X<const Y> can be called with an argument of type X<Y>:

template <class T>
class X {
public:
    X(const X& other) = default;

    X(const X<std::remove_const_t<T>>& other)
    requires (!std::is_const_v<T>)
    : p(other.getY()) {}

    T* getY() const;
private:
    T* p;
};

If you want to hide the templatedness from the users, you can do so like this:

namespace detail {
template <class T>
class X_impl {
public:
    X_impl(const X_impl& other) = default;

    X_impl(const X_impl<std::remove_const_t<T>>& other)
    requires (!std::is_const_v<T>)
    : p(other.getY()) {}

    T* getY() const;
private:
    T* p;
};
}  // namespace detail

using X = X_impl<Y>;
using CX = X_impl<const Y>;
Sign up to request clarification or add additional context in comments.

2 Comments

I knew about templates, but I wondered if there was a simpler solution, but the part about hiding the template is very interesting. Is that a common design pattern?
@m_ognjen I don't think anything I wrote here is particularly uncommon. I don't know if it's a design pattern with a well-known name, though.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.