• C++中的Union



      我们应该按照C中的convention去使用union,这是我这篇文章要给出的观点。虽然C++使得我们可以扩展一些新的东西进去,但是,我建议你不要那样去做,看完这篇文章之后,我想你大概也是这么想的。
      C由于没有类的概念,所有类型其实都可以看作是基本类型的组合,因此在union中包含struct也就是一件很自然的事情了,到了C++之后,既然普遍认为C++中的struct与class基本等价,那么union中是否可以有类成员呢?先来看看如下的代码:

      struct TestUnion
      {
          TestUnion() {}
      };

      typedef  union
      {
          TestUnion obj;
      } UT;

      int main (void)
      {
          return 0;
      }
      编译该程序,我们将被告知:
      error C2620: union '__unnamed' : member 'obj' has user-defined constructor or non-trivial default constructor
      而如果去掉那个什么也没干的构造函数,则一切OK。

      为什么编译器不允许我们的union成员有构造函数呢?我无法找到关于这个问题的比较权威的解释,对这个问题,我的解释是:

       如果C++标准允许我们的union有构造函数,那么,在进行空间分配的时候要不要执行这个构造函数呢?如果答案是yes,那么如果TestUnion 的构造函数中包含了一些内存分配操作,或者其它对整个application状态的修改,那么,如果我今后要用到obj的话,事情可能还比较合理,但是如果我根本就不使用obj这个成员呢?由于obj的引入造成的对系统状态的修改显然是不合理的;反之,如果答案是no,那么一旦我们今后选中了obj来进行 操作,则所有信息都没有初始化(如果是普通的struct,没什么问题,但是,如果有虚函数呢?)。更进一步,假设现在我们的union不是只有一个 TestUnion obj,还有一个TestUnion2 obj2,二者均有构造函数,并且都在构造函数中执行了一些内存分配的工作(甚至干了很多其它事情),那么,如果先构造obj,后构造obj2,则执行的 结果几乎可以肯定会造成内存的泄漏。

      鉴于以上诸多麻烦(可能还有更多麻烦),在构造union时,编译器只负责分配空间,而不负责去执行附加的初始化工作,为了简化工作,只要我们提供了构造函数,就会收到上面的error。

    同理,除了不能加构造函数,析构函数/拷贝构造函数/赋值运算符也是不可以加。

      此外,如果我们的类中包含了任何virtual函数,编译时,我们将收到如下的错误信息:
      error C2621: union '__unnamed' : member 'obj' has copy constructor

      所以,打消在union中包含有构造函数/析构函数/拷贝构造函数/赋值运算符/虚函数的类成员变量的念头,老老实实用你的C风格struct吧!
      不过,定义普通的成员函数是OK的,因为这不会使得class与C风格的struct有任何本质区别,你完全可以将这样的class理解为一个C风格的struct + n个全局函数。

      现在,再看看在类中包含内部union时会有什么不同。看看下面的程序,并请注意阅读程序提示:

      class TestUnion
      {
          union DataUnion
          {
              DataUnion(const char*);
              DataUnion(long);
              const char* ch_;
              long l_;
          } data_;

      public:
          TestUnion(const char* ch);
          TestUnion(long l);
      };

       TestUnion::TestUnion(const char* ch) : data_(ch) // if you want to use initialzing list to initiate a                                                                nested-union member, the union must not be anonymous and                                                            must have a constructor。
      {}

      TestUnion::TestUnion(long l) : data_(l)
      {}

      TestUnion::DataUnion::DataUnion(const char* ch) : ch_(ch)
      {}

      TestUnion::DataUnion::DataUnion(long l) : l_(l)
      {}

      int main (void)
      {
          return 0;
      }

      正如上面程序所示,C++中的union也可以包含构造函数,但是,这虽然被语言所支持,但实在是一种不佳的编程习惯,因此,        我不打算对上面的程序进行过多的说明。我更推荐如下的编程风格:

      class TestUnion
      {
          union DataUnion
          {
              const char* ch_;
              long l_;
          } data_;
      
      public:
          TestUnion(const char* ch);
          TestUnion(long l);
      };

      TestUnion::TestUnion(const char* ch)
      {
          data_.ch_ = ch;
      }

      TestUnion::TestUnion(long l)
      {
          data_.l_ = l;
      }

      int main (void)
      {
          return 0;
      }

      它完全是C风格的。

      所以,接受这个结论吧:
      请按照C中的convention去使用union,尽量不要尝试使用任何C++附加特性。



        union是个好东西,union是个struct,里面所有成员共享一块内存,大小由size最大的member决定,存取成员的时候会以成员的类型来解析这块内存;在gamedev中,union可以在这些方面有所作为:
        1. 换名:
        struct Rename
        {
        public:
            union
            {
                struct
                {
                    float x,y,z,w;
                };
                struct
                {
                    float vec[4];
                };
            };
        };
     这样我们既可以根据具体的含义来访问变量,也可以象数组一样的loop;

     2 .压缩:
     struct Compression
     {
      public:
          bool operator==(const Compression& arg) const { return value == arg.value; }
          union
          {
              struct
              {
                 char a,b,c,d,e,f,g;
              };
              struct
              {
                 long long value;
              };
          };
      };
    这样对于集中处理的情况,比如==,就会大幅度提高效率,象在64位机上,只要一次,或者传输数据的情况,压缩解压缩都非常方便;
    3. 危险:
    匿名的union用法,不是standard,所以在compiler上要确认==>编译器移植性不好;
    不同的机器操作系统上数据的size都是不一样,表示不一样,那么在用union的时候,尤其是在移植的时候,都是危险的情况;
    但是如果系统,compiler都是一样的话,在合适的地方使用union还是可以的。

  • 相关阅读:
    开源的免费的对比工具
    win10 git bash 配置
    Java SSH 不使用终端也能调用环境变量中的指令
    MySQL WITH ROLLUP
    docker安装postgres
    开源的应用容器引擎
    清除浮动有哪几种方法
    js中的yield
    git的速学了解
    string/stringBuffer/StringBuilder的区别
  • 原文地址:https://www.cnblogs.com/kex1n/p/2286453.html
Copyright © 2020-2023  润新知