Home > Articles > Programming > C/C++

  • Print
  • + Share This
This chapter is from the book

Guru Questions

  1. The article [Manley02] cites the motivating case of writing a scripting language: Say that you want your language to support a single type for variables that at various times can hold an integer, a string, or a list. Creating a union { int i; list<int> l; string s; }; doesn't work for the reasons covered in Questions 1 and 2. The following code presents a workaround that attempts to support allowing any type to participate in a union. (For a more detailed explanation, see the original article.)

    Critique this code and identify:

    1. Mechanical errors, such as invalid syntax or nonportable conventions.

    2. Stylistic improvements that would improve code clarity, reusability, and maintainability.

      #include <list>
      #include <string>
      #include <iostream>
      using namespace std;
      
      #define max(a,b) (a)>(b)?(a):(b)
      
      typedef list<int> LIST;
      typedef string STRING;
      
      struct MYUNION {
        MYUNION() : currtype(NONE) {}
        ~MYUNION() {cleanup();}
      
        enum uniontype {NONE,_INT,_LIST,_STRING};
        uniontype currtype;
        inline int& getint();
        inline LIST& getlist();
        inline STRING& getstring();
      
      protected:
        union {
         int i;
         unsigned char buff[max(sizeof(LIST),sizeof(STRING))];
        } U;
      
        void cleanup();
       };
      
       inline int& MYUNION::getint()
       {
        if(currtype==_INT) {
          return U.i;
        } else {
          cleanup();
          currtype=_INT;
          return U.i;
        } // else
       }
      
       inline LIST& MYUNION::getlist()
       {
        if(currtype==_LIST) {
         return *(reinterpret_cast<LIST*>(U.buff));
        } else {
          cleanup();
          LIST* ptype = new(U.buff) LIST();
          currtype=_LIST;
          return *ptype;
        } // else
       }
      
       inline STRING& MYUNION::getstring()
       {
        if(currtype==_STRING) {
         return *(reinterpret_cast<STRING*>(U.buff));
         } else {
           cleanup();
           STRING* ptype = new(U.buff) STRING();
           currtype=_STRING;
           return *ptype;
        } // else
       }
       void MYUNION::cleanup()
       {
        switch(currtype) {
         case _LIST: {
         LIST& ptype = getlist();
         ptype.~LIST();
         break;
        } // case
        case _STRING: {
         STRING& ptype = getstring();
         ptype.~STRING();
         break;
         } // case
         default: break;
        } // switch
        currtype=NONE;
       }
      
  2. Show a better way to achieve a generalized variant type, and comment on any tradeoffs you encounter.

  • + Share This
  • 🔖 Save To Your Account