gcc: How to use __attribute((__may_alias__)) properly to avoid “derefencing type-punned pointer” warning

后端 未结 3 1830
被撕碎了的回忆
被撕碎了的回忆 2021-02-06 17:41

I\'ve got some code that uses type-punning to avoid having to call a member \"object\"\'s constructor and destructor unless/until it\'s actually necessary to use the object.

相关标签:
3条回答
  • 2021-02-06 17:56

    I think the typedef is confusing GCC. These sorts of attributes seem to work best when applied directly to variable definitions.

    This version of your class works for me (GCC 4.6.0):

    template<class T> class Lightweight
    {
    private:
      //  typedef T __attribute((__may_alias__)) T_may_alias;
    
    public:
      Lightweight() : _isObjectConstructed(false) {/* empty */}
    
      ~Lightweight()
      {
        // call object's destructor, only if we ever constructed it
        if (_isObjectConstructed) {
          T * __attribute__((__may_alias__)) p
            = (reinterpret_cast<T *>(_optionalObject._buf));
          p->~T();
        }
      }
    
      void MethodThatGetsCalledOften()
      {
        // Imagine some useful code here
      }
    
      void MethodThatGetsCalledRarely()
      {
        T * __attribute__((__may_alias__)) p
          = (reinterpret_cast<T *>(_optionalObject._buf));
        if (_isObjectConstructed == false)
          {
            // demand-construct the heavy object, since we actually need to use it now
    
            (void) new (p) T();
            _isObjectConstructed = true;
          }
          p->DoSomething();
      }
    
      [etc.]
    
    0 讨论(0)
  • 2021-02-06 18:12

    I would argue for having your containing class just contain a char array of sufficient size to contain your member "object" and then using placement new to initialize on top of the char array. That has the perk of being specification-compliant as well as cross-compiler. The only problem is that you have to know the size in chars of your member object, which may get you in trouble.

    Is there a reason you can't have the member be a pointer and use new and delete?

    0 讨论(0)
  • 2021-02-06 18:16

    What if you replace _isObjectConstructed with a pointer to the object:

    class Lightweight
    {
    public:
       Lightweight() : object(NULL) {/* empty */}
    
       ~Lightweight()
       {
          // call object's destructor, only if we ever constructed it
          if (object) object->~T();
       }
    
       void MethodThatGetsCalledOften()
       {
          // Imagine some useful code here
       }
    
       void MethodThatGetsCalledRarely()
       {
          if (!object)
          {
             // demand-construct the heavy object, since we actually need to use it now
             object = new (_optionalObject._buf) T();
          }
          object->DoSomething();
       }
    
    private:
       union {
          char _buf[sizeof(T)];
          unsigned long long _thisIsOnlyHereToForceEightByteAlignment;
       } _optionalObject;
    
       T *object;
    };
    

    Note, no GCC extension, only pure C++ code.

    Using a T* instead of a bool won't even make Lightweight any bigger!

    0 讨论(0)
提交回复
热议问题