Search code examples
c++constants3dsmax

What's the best way to deal with a non-const-aware Library/SDK?


I've been working for longer now with the 3ds max SDK, which in nearly all parts doesn't use const at all. So even a Width() or Height() getter of a Bitmap isn't marked as const. This has been already a real annoyance in small projects, but since I've been working on a larger project, it becomes increasingly terrible.

For example, I am holding a single Bitmap instance as a shared_ptr<Bitmap> member in multiple class instances out of performance reasons. Of course there are cases I want to avoid by all means that a single instance may change the properties for all instances, thus all raw pointer getters (necessary for the SDK) deliver a const Bitmap*. Unfortunately, now I can't even ask the const Bitmap* for its width - because Width() is non-const.

I'm asking myself what is the best way to deal with this. I see three options:

  • Forget about const completely, make everything non-const. In the smaller projects I used to do this, but like I said, with more sophisticated techniques, it becomes more dangerous.
  • Make an inplace const_cast at every place it's necessary. That will be at many places, and it's pretty bad to read.
  • Write wrappers for the 3ds max classes, which provide const methods at least for the methods which are highly presumably safe. This would encapsulate all the const_cast in one place and be also suitable for other projects.

I have been warned (and I know) that this might be opinion-based. But I had to deal with this annoying problem for a long time now, and I'd really like to find a solution and thus need the experience of others.


Solution

  • First of all, I would like to mention that lack of const correctness may be justifiable by implementation details, for example getter function may perform lock on internal synchronization primitive and therefore always alters internal state and can not be marked as const:

    int Bitmap::Width(void)
    {
         int width{};
         ::std::lock_guard<::std::mutex> const lock{m_sync};
         width = m_width;
         return width;
    }
    

    As a workaround you can write a dedicated PImpl bitmap wrapper restricting direct access to bitmap implementation forwarding functions of interest with appropriate const qualifiers:

    class SharedBitmap
    {
        private: ::std::shared_ptr<Bitmap> m_p_bitmap;
    
        public: int Width(void) const
        {
            return m_p_bitmap->Width();
        }
    
        // other methods...
    };
    

    Note that this approach is different from third option listed in question as it does not involve const_cast.