C++中使用union的几点思考

大卫注:
这段时间整理旧资料,看到一些文章,虽然讲的都是些小问题,不大可能用到,但也算是一个知识点,特整理出来与大家共享.与此相关的那篇文章的作者的有些理解是错误的,我写此文,也是纠正为了作者的一些错误认识.当然,如果我的理解有任何错误,也恳请大家批评指正.

C++虽说被B.S.称作一门新语言,但它毕竟与C有着千丝万缕的联系,虽然B.S.一再坚持,但我还是愿意把C++看作是C ++.
我们应该按照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++附加特性.

C++中使用union的几点思考(转)的更多相关文章

  1. Ms SQLServer中的Union和Union All的使用方法和区别

    Ms SQLServer中的Union和Union All的使用方法和区别 SQL UNION 操作符 UNION 操作符用于合并两个或多个 SELECT 语句的结果集. 请注意,UNION 内部的 ...

  2. Oracle中的Union、Union All、Intersect、Minus

    Oracle中的Union.Union All.Intersect.Minus  众所周知的几个结果集集合操作命令,今天详细地测试了一下,发现一些问题,记录备考. 假设我们有一个表Student,包括 ...

  3. golang 中的 sizeof 以及 golang中的 union

    golang 中的 sizeof: 1: int(unsafe.Sizeof(uint32(0))) 2: int(reflect.TypeOf(uint32(0)).Size()) golang中的 ...

  4. Boost--variant (C++中的union)

    union联合体类型的问题 只能用于内部类型,这使得union在C++中几乎没有用 所以boost提供了variant,相当于是C++中的union #include "boost/vari ...

  5. mysql中的union操作(整理)

    mysql中的union操作(整理) 一.总结 一句话总结: union两侧的字段数和字段类型要是一样的 union可以接多个 orderby和排序可以在最后的union组合之后 1.union简单实 ...

  6. OpenGL shader 中关于顶点坐标值的思考

    今天工作中需要做一个事情: 在shader内部做一些空间距离上的计算,而且需要对所有的点进行计算,符合条件的显示,不符合条件的点不显示. 思路很简单,在vertex shader内知道顶点坐标,进行计 ...

  7. 由项目中一个hash2int函数引发的思考

    hash2int /** * 计算一个字符串的md5折算成int返回 * @param type $str * @return type */ function hash2int($str) { $m ...

  8. SQL语句中:UNION与UNION ALL的区别

    有些人看到题目,瞬间觉得楼主也太弱了吧,这种问题也要拿出来写,这种问题 随便会点sql 的人基本都会 Union   是会删除冗余数据 Union ALL 不会删除冗余数据 将所有的结果都展现给用户 ...

  9. C#Linq中的Union All/Union/Intersect和Top/Bottom和Paging和SqlMethods,skip,take,takewhile,skipwhile,编译查询等

    我们继续讲解LINQ to SQL语句,这篇我们来讨论Union All/Union/Intersect操作和Top/Bottom操作和Paging操作和SqlMethods操作 . Union Al ...

随机推荐

  1. HDU 5883 The Best Path

    The Best Path Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)Tot ...

  2. ylbtech-权限管理-数据库设计-功能权限管理技术

    ylbtech-DatabaseDesgin:ylbtech-权限管理-数据库设计-功能权限管理技术 DatabaseName:ylb_permission(权限管理-功能权限管理技术)实现 Type ...

  3. CSS使用简介

    1.CSS 指层叠样式表 (Cascading Style Sheets) 2.说明: 样式定义如何显示 HTML 元素:     样式通常存储在样式表中:     把样式添加到 HTML 4.0 中 ...

  4. QT多线程笔记

    1.QT多线程涉及到主线程和子线程之间交互大量数据的时候,使用QThread并不方便,因为run()函数本身不能接受任何参数,因此只能通过信号和槽的交互来获取数据,如果只是单方面简单交互数据还过得去, ...

  5. 使用jQuery Mobile实现通讯录

    jQuery Mobile 通讯录 拨打电话作者:方倍工作室 地址: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional/ ...

  6. codeforce 702C Cellular Network 二分答案

    http://codeforces.com/contest/702 题意:n个村庄,m个机站,问机站最短半径覆盖完所有村庄 思路:直接二分答案 二分太弱,调了半天..... // #pragma co ...

  7. 一起刷LeetCode1-Two Sum

    感觉有必要重新刷刷题了,为以后找工作做做准备,选择LeetCode+topcoder上的Data Science Tutorials, 争取每天晚上10:00开始刷一道,复习一下相关知识点. ---- ...

  8. YARN应用场景、原理与资源调度

    1.Hadoop YARN产生背景 源于MapReduce1.0 运维成本 如果采用“一个框架一个集群”的模式,则可能需要多个管理员管理这些集群,进而增加运维成本,而共享模式通常需要少数管理员即可完成 ...

  9. web.py实现jsonp

    浏览器端请求 $.getJSON("/currenttime?callback=?", function (json){ $("#time").html(jso ...

  10. Codeforces Round #364 (Div.2) C:They Are Everywhere(双指针/尺取法)

    题目链接: http://codeforces.com/contest/701/problem/C 题意: 给出一个长度为n的字符串,要我们找出最小的子字符串包含所有的不同字符. 分析: 1.尺取法, ...