operator new overloading and alignment

前端 未结 2 620
情深已故
情深已故 2020-12-12 21:08

I\'m overloading operator new, but I recently hit a problem with alignment. Basically, I have a class IBase which provides operator new

2条回答
  •  渐次进展
    2020-12-12 21:46

    This is a possible solution. It will always choose the operator with the highest alignment in a given hierarchy:

    #include 
    #include 
    #include 
    
    // provides operators for any alignment >= 4 bytes
    template
    struct DeAllocator;
    
    template
    struct DeAllocator : virtual DeAllocator {
      void *operator new(size_t s) throw (std::bad_alloc) {
        std::cerr << "alignment: " << Alignment << "\n";
        return ::operator new(s);
      }
    
      void operator delete(void *p) {
        ::operator delete(p);
      }
    };
    
    template<>
    struct DeAllocator<2> { };
    
    // ........... Test .............
    // different classes needing different alignments
    struct Align8 : virtual DeAllocator<8> { };
    struct Align16 : Align8, virtual DeAllocator<16> { };
    struct DontCare : Align16, virtual DeAllocator<4> { };
    
    int main() {
      delete new Align8;   // alignment: 8
      delete new Align16;  // alignment: 16
      delete new DontCare; // alignment: 16
    }
    

    It's based on the dominance rule: If there is an ambiguity in lookup, and the ambiguity is between names of a derived and a virtual base class, the name of the derived class is taken instead.


    Questions were risen why DeAllocator inherits DeAllocator. The answer is because in a given hierarchy, there may be different alignment requirements imposed by classes. Imagine that IBase has no alignment requirements, A has 8 byte requirement and B has 16 byte requirement and inherits A:

    class IBAse { };
    class A : IBase, Alignment<8> { };
    class B : A, Alignment<16> { };
    

    Alignment<16> and Alignment<8> both expose an operator new. If you now say new B, the compiler will look for operator new in B and will find two functions:

                // op new
                Alignment<8>      IBase
                     ^            /
                      \         /
                        \     /
     // op new            \ /
     Alignment<16>         A
                \         /
                  \     /
                    \ /
                     B 
    
    B ->      Alignment<16>  -> operator new
    B -> A -> Alignment<8> -> operator new
    

    Thus, this would be ambiguous and we would fail to compile: Neither of these hide the other one. But if you now inherit Alignment<16> virtually from Alignment<8> and make A and B inherit them virtually, the operator new in Alignment<8> will be hidden:

                // op new
                Alignment<8>      IBase
                     ^            /
                    / \         /
                  /     \     /
     // op new  /         \ /
     Alignment<16>         A
                \         /
                  \     /
                    \ /
                     B 
    

    This special hiding rule (also called dominance rule) however only works if all Alignment<8> objects are the same. Thus we always inherit virtually: In that case, there is only one Alignment<8> (or 16, ...) object existing in any given class hierarchy.

提交回复
热议问题