سؤال

Let us assume I have the following C++ class:

class MyFastMessageEncoder
{
public:
    MyFastMessageEncoder() :
        m_fieldEncoder(ENCODING_STYLE_DEFAULT)
    {
    }

    void set_encoding_style(const EncodingStyle encodingStyle)
    {
        m_fieldEncoder.set_encoding_style(encodingStyle);
    }

    EncodingStyle get_encoding_style() const
    {
        return m_fieldEncoder.get_encoding_style();
    }

    void encode(const UnencodedFieldList &unencodedFieldList, Message &message
    {
        for (UnencodedFieldList::const_iterator it = unencodedFieldList.begin(), end = unencodedFieldList.end(); it != end; ++it)
        {
            m_fieldEncoder.set_raw_data(*it);
            message.add_field(m_fieldEncoder.encode());
        }
    }

private:
    FieldEncoder    m_fieldEncoder;
};

The MyFastMessageEncoder class is required to be extremely efficient (encoding will be performed on tens of thousands of messages per second), the time required to instantiate the FieldEncoder object is a non-negligible cost, so to solve the issue, I have defined the FieldEncoder object as a class member, and initialized it inside the constructor just once.

My issue is that FieldEncoder::SetRawData() is a non-const method, which means that the MyFastMessageEncoder::encode method must also be non-const. However, if I were to make the FieldEncoder object a temporary inside the method, MyFastMessageEncoder::encode could be flagged as const. This means that every object that calls MyFastMessageEncoder::encode is also non-const, which (to me) just starts ruining the program's const-correctness.

Now I understand how the mutable keyword works works, and how I could use it to solve this problem, but my question is: Would doing so be considered bad form, since the internals of the object are technically being modified?

Other considerations:

  • Thread-safety is not a concern, this is guaranteed to only run in a single thread (although the MyFastMessageEncoder may be created on multiple threads)
  • The set_raw_data method does not impact the FieldEncoder class outside the MyFastMessageEncoder::encode method. Any data that is set is cleared or overwritten the next time the set_raw_data method is called.
هل كانت مفيدة؟

المحلول

If encoding depends on previous fields, then MyFastMessageEncoder::encode is obviously non-const as it changes the observable state of the instance - calling it twice won't give the same result, therefore the state of the instance has changed, therefore it should be non-const.

Otherwise it seems a bit odd that you have, in the FieldEncoder, both a costly initialisation and that the state following set_raw_data is governed only by the data that's set. This suggests to me that the initialisation cost might be reduced - either sharing some of whatever structures are set up, or by pooling encoders.

However, both of those refactorings would be much more involved than making the encoder mutable, so if the initialisation cost is not causing problems elsewhere I would comment that the encoder only exists as a member as an optimisation for encode and make it mutable.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى softwareengineering.stackexchange
scroll top