Search code examples
c++inheritancecode-duplicationboilerplate

How to elegantly avoid code duplication, when class T and T_ref only differ in the constructors & destructors?


class HugeTpool{            // Owner of *_dataPool memory
    int x;
    int y; 
//   ...  etc;      // Data Members (many)
   size_t* _dataPool;        // pointer to huge contiguous data

    T_ref operator[](int i){    // used to emulate vector<T> like behaviour
    /* Implementation  details*/
    return T_ref_Obj;
    }
};

class T{                    // Owner of *_data memory
    int a;
//    ... etc;       //  Data Members   (few)
    size_t* _data;           // pointer to small contiguous data
   
    T operator+(T){}
//      ... etc;     //  Member functions

// Glue code to enable interoperability with class T_ref
    T operator+(T_ref){}
//    ... etc;
};

class T_ref{                // A reference type, to emulate T class interfaces 
    int a;
//    ... etc;        //  Data Members  (Identical to class T)  
    size_t* _data;          // Does not own *_data memory, only references it

    T operator+(T_ref);
//      ... etc;        //  Member functions (Identical to class T)    

// Glue code to enable interoperability with class T
    T operator+(T){}
//    ... etc;
};

Here the vector<T> like interface is being emulated upon the underlying HugeTpool data structure, with the help of T_ref class. T and T_ref only defer in the management of *_data memory. The memory pointed to by T_ref must not be freed upon the destruction of a T_ref obj. The two classes only defer in copy & move constructors, destructors and assignment operators, and the rest of it is the same.

As T and T_ref are in essence the same, I need T and T_ref to be interoperable. which is requiring a lot of glue and boilerplate code. Also, as both class have the same interfaces (and member funcitons), there is a lot of code duplication. Is there an elegant to work around this problem? I have considered inheritence, but it does not seem to suit well for this scenario.

This is a simplified version of my problem, in practice, I have many _ref classes and they need to be interoperable with each other. The glue code required to accomplish this is quickly getting out of control.


Solution

  • It may be that you should be using T & not T_ref, or if you need it to be a regular type, std::reference_wrapper<T>.

    If that isn't the case, write a borrow_ptr template, very similar to unique_ptr except that it also tracks if it doesn't own it's element. Then use borrow_ptr<size_t> data; in T, and discard T_ref.

    As a sketch

    template <typename T>
    class borrow_ptr 
    {
        std::unique_ptr<T> data;
        bool owns;
    public:
        ~borrow_ptr() { if (!owns) data.release(); }
        // public surface of unique_ptr
    };