0

I have an "item" whose data can be represented 3 ways. I can convert from one representation to any of the others, at a runtime cost. Once I do the conversion I'd like to keep the new representation around. Any representation of the data can be converted to any of the others without "modifying" the core data. Because of the runtime cost, I want a class that contains 3 representations of the data. At any time, 1 to 3 of them will be valid.

The real point of this is because it also has access methods, where the user can ask for something. This something can be gotten from 1 or possibly more of the representations. For example, you could get the "range" from representation1 and the "volume" from representations 2 or 3.

My solution was to create class with the 3 representations as member data (and a way to know if they are valid). Then I created a getRange() method that internally knows which representation it needs and creates that if necessary. This works fine and solves all my issues except that the get method cannot be const.

So the real issue with this solution is that even a "constant" instance of this class is not really const because it internally might create other representations. However it really is "constant" because changing representations does not modify the core data.

Is there a C++ design pattern that might help with this class? Any suggestions?

user3375624
  • 43
  • 1
  • 6

2 Answers2

3

My solution was to create class with the 3 representations as member data (and a way to know if they are valid). Then I created a getRange() method that internally knows which representation it needs and creates that if necessary. This works fine and solves all my issues except that the get method cannot be const.

This is the very purpose of the mutable type specified! In order to be able to update the internal representation while still having a const method, make the representation attributes mutable:

struct A {

    int get_range() const {
        if (!_repr2.is_valid()) {
            _repr2 = Repr2(_repr1); // I am in a const method, but still
                                    // I can update a mutable attribute
        }
        return _repr2.get_range();
    }    

private:
    mutable Repr1 _repr1;
    mutable Repr2 _repr2;
};

Here is a full example with two representations that uses std::unique_ptr to store the representation so you can easily check if one is instanciated or not.

Holt
  • 36,600
  • 7
  • 92
  • 139
1

As per Holt's answer, mutable is the main thing needed here. You may also benefit from boost::optional<ReprX> for storing the representations. This helps with the 'a way to know if they are valid' part of your problem:

struct A {

    int get_range() const {
        if (!_repr2) {
            _repr2 = Repr2(*_repr1); 
        }
        return _repr2->get_range();
    }    

private:
    mutable boost::optional<Repr1> _repr1;
    mutable boost::optional<Repr2> _repr2;
};
SimonD
  • 638
  • 5
  • 16
  • I like this also! My code already uses boost, so I will do it this way. Thank you! – user3375624 Apr 29 '16 at 16:36
  • The other nice thing about boost::optional is that it does not call the default constructor of the class. I had to use this because the runtime speed without it dropped significantly. It turned out that the default constructors of the representations (coming from a library I cannot control) were very slow and actually affected the runtime speed. By just switching to use boost::optional it fixed the problem. Nice! – user3375624 May 09 '16 at 13:58