热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Boost源码剖析之:泛型指针类any之海纳百川

Boost源码剖析之:泛型指针类any之海纳百川作者:ppLiu(刘未鹏)C是强类型语言,所有强类型语言对型别的要求都是苛刻
Boost源码剖析之:泛型指针类any之海纳百川
作者:ppLiu(刘未鹏)

C++是强类型语言,所有强类型语言对型别的要求都是苛刻的,型别一有不合编译器就会抱怨说不能将某某型别转换为某某型别,当然如果在型别之间提供了转换操作符或是标准所允许的一定程度的隐式转换(如经过非explicit构造函数创建临时变量的隐式转换或是在int,long这些基本型别间的)又另当别论。总的说来,为了保持型别安全,C++有严厉的要求。然而有时候程序员可能有这样的需要:

i;
iong j;
X x;
any anyVal=i;
...
anyVal=j;
...
anyVal=x;
...

考虑这样的一个“泛型指针类”该如何设计是很有趣的事情。

1.它本身不能是模板类,因为如果它是模板,你必须为它的具现化提供模板参数。而事实上你并不想这样做。你想让同一个对象接受任意型别的数据。在上面的代码中这个对象是anyVal。然而,如果你必须为它提供模板参数,那么上面的代码看起来就会像这样:

any<> anyIntVal&#61;i;
any<> anyLongVal&#61;j;
...

这显然已经丧失了anyVal的优势----以单个对象接受所有型别的数据。与其这样还不如直接写:

anyIntVal&#61;i;anyLongVal&#61;j;

所以&#xff0c;any不能是模板类。

2&#xff0e;它必须提供某些有关它所保存的对象型别的信息。

3. 它必须提供某种方法将它保存的数值“取出来”。

事实上&#xff0c;Boost库已经提供了这样的类boost::any&#xff0c;下面我就为你讲述它的原理及构造。

首先&#xff0c;any类里面一定要提供一个模板构造函数和模板operator&#61;操作符。因为你必须允许用户写出&#xff1a;

any any_value(val);
any_value&#61;val1;

这样的代码。

其次&#xff0c;数据的存放之所是个问题&#xff0c;显然你不能将它保存在any类中&#xff0c;那会导致any类成为模板类&#xff0c;后者是明确不被允许的。数据应该动态存放&#xff0c;即动态分配一个数据的容器来存放数据&#xff0c;而any类中则保存指向这个容器的指针&#xff0c;明确地说&#xff0c;是指向这个容器的基类的指针&#xff0c;这是因为容器本身必须为模板&#xff0c;而any类中的指针成员又必须不是泛型的(因为any不能是泛型的&#xff0c;所以any中所有数据成员都不能是泛型的)&#xff0c;所以&#xff0c;结论是&#xff1a;为容器准备一个非泛型的基类&#xff0c;而让指针指向该基类。

下面就看一看boost库是如何具体实现这两点的。

any
{
:placeholder
{
:
virtual ~placeholder()
{}
:
virtual std::type_info & type() &#61; 0;
virtual placeholder * clone() &#61; 0;
};
holder : placeholder
{
:
holder( ValueType & value)
: held(value)
{}
:
virtual std::type_info & type()
{(ValueType); }
virtual placeholder * clone()
{holder(held);
}
:
ValueType held;
};
placeholder * content;

any( ValueType & value)
: content( holder(value)) {}
...

any & &#61;( ValueType & rhs)
{
any(rhs).swap(*); *;
}
any & swap(any & rhs)
{
std::swap(content, rhs.content); *;
}
~any()
{content; }
...
};

这虽然并非any的全部源代码&#xff0c;但是所有重要的思想已经表露无遗。剩下的部分只是一些简单的细节&#xff0c;请参见boost库的原文件。

“但是等等&#xff01;”&#xff0c;你急切的说&#xff1a;“你失去了型别的信息。”唔...的确&#xff0c;当赋值的模板函数返回后你也就失去了关于型别的信息。考虑下面你可能想要写出的代码&#xff1a;

i&#61;10;
boost::any anyVal&#61;i;j&#61;anyVal;

当转换操作符的设想彻底失败后&#xff0c;我们只能借助于某些“外来”的显式转换操作。就向static_cast<>一样。Boost提供了any_cast<>&#xff0c;于是你可以这样写&#xff1a;

j&#61;any_cast<>(anyVal);

事实上&#xff0c;any_cast的代码是这样的&#xff1a;


ValueType any_cast( any & operand)
{ValueType * result &#61; any_cast(&operand);(!result) bad_any_cast(); *result;
}

而any_cast针对指针的版本是这样&#xff1a;


ValueType * any_cast(any * operand)
{operand && operand->type() &#61;&#61; (ValueType) 1 ? & *>(operand->content)->held:0; }

这两个any_cast版本应该很好理解。后版本中的型别检查是必要的&#xff0c;如果没有这个检查&#xff0c;考虑以下代码&#xff1a;

i&#61;10;
boost::any anyVal&#61;i;d&#61;any_cast<>(anyVal);

这将通过编译&#xff0c;且运行期通常竟然也不会出错&#xff0c;下面我为你解释为什么会这样。

boost::anyVal&#61;i;其实将anyVal.content指针指向了一个holder对象(请回顾上面的代码)。然后any_cast(anyVal)实际上调用了any_cast<>针对指针的重载版本&#xff0c;并将anyVal的地址传递过去&#xff0c;也就是转到1处&#xff0c;因为调用的是any_cast&#xff0c;所以1处的代码被编译器特化为

2 *>(operand->content)->held

但是前面说过&#xff0c;operand->content实际指向的是any::holder&#xff0c;所以这个static_cast<>是“非法”的&#xff0c;然而事实是&#xff1a;它能通过编译&#xff01;原因很简单&#xff0c;holder和holder都是placeholder的基类。将基类指针向派生类指针转换被认为是合法的。但这却酿成大错&#xff0c;因为表达式2的型别将因此被推导为double&#xff01;原先holder只给int held;成员分配了sizeof(int)个字节的内存&#xff0c;而现在却要将int型的held当作double型来使用&#xff0c;也就是说使用sizeof(double)个字节内存。所以这就相当于&#xff1a;

i&#61;10;
* pd&#61;(*)(*)&i;d&#61;*pd;

使用typeinfo让我们有可能在运行时发现这种型别不符并及时抛出异常。但有个违反直观的事情是上面的那行错误的代码仍能通过编译&#xff0c;并且你也无法阻止它通过编译&#xff0c;因为holder和holder都是placeholder的基类。所以只能期望程序员们清楚自己在做什么&#xff0c;要不然就给他个异常瞧瞧。

使用boost::any实现virtual template成员函数

如你所知&#xff0c;C&#43;&#43;中没有提供virtual template function。然而有时候你的确会有这种需要,any可以一定程度上满足这种需要&#xff0c;例如&#xff0c;

Base
{
:
virtual Accept(boost::any anyData)
{
...
}
};Derived: Base
{:
virtual Accept(boost::any anyData)
{
...
}
};

这样的Accept函数能够接受任意类型的数据&#xff0c;并且是virtual函数

posted on 2009-01-09 18:46 GXW 阅读(...) 评论(...) 编辑 收藏

转:https://www.cnblogs.com/Fancyboy2004/archive/2009/01/09/1372954.html



推荐阅读
  • 本文详细介绍了 PHP 中对象的生命周期、内存管理和魔术方法的使用,包括对象的自动销毁、析构函数的作用以及各种魔术方法的具体应用场景。 ... [详细]
  • 在软件开发过程中,经常需要将多个项目或模块进行集成和调试,尤其是当项目依赖于第三方开源库(如Cordova、CocoaPods)时。本文介绍了如何在Xcode中高效地进行多项目联合调试,分享了一些实用的技巧和最佳实践,帮助开发者解决常见的调试难题,提高开发效率。 ... [详细]
  • C++ 开发实战:实用技巧与经验分享
    C++ 开发实战:实用技巧与经验分享 ... [详细]
  • ButterKnife 是一款用于 Android 开发的注解库,主要用于简化视图和事件绑定。本文详细介绍了 ButterKnife 的基础用法,包括如何通过注解实现字段和方法的绑定,以及在实际项目中的应用示例。此外,文章还提到了截至 2016 年 4 月 29 日,ButterKnife 的最新版本为 8.0.1,为开发者提供了最新的功能和性能优化。 ... [详细]
  • JUC(三):深入解析AQS
    本文详细介绍了Java并发工具包中的核心类AQS(AbstractQueuedSynchronizer),包括其基本概念、数据结构、源码分析及核心方法的实现。 ... [详细]
  • 在多线程并发环境中,普通变量的操作往往是线程不安全的。本文通过一个简单的例子,展示了如何使用 AtomicInteger 类及其核心的 CAS 无锁算法来保证线程安全。 ... [详细]
  • 在HTML布局中,即使将 `top: 0%` 和 `left: 0%` 设置为元素的定位属性,浏览器中仍然会出现空白填充。这个问题通常与默认的浏览器样式、盒模型或父元素的定位方式有关。为了消除这些空白,可以考虑重置浏览器的默认样式,确保父元素的定位方式正确,并检查是否有其他CSS规则影响了元素的位置。 ... [详细]
  • 在过去,我曾使用过自建MySQL服务器中的MyISAM和InnoDB存储引擎(也曾尝试过Memory引擎)。今年初,我开始转向阿里云的关系型数据库服务,并深入研究了其高效的压缩存储引擎TokuDB。TokuDB在数据压缩和处理大规模数据集方面表现出色,显著提升了存储效率和查询性能。通过实际应用,我发现TokuDB不仅能够有效减少存储成本,还能显著提高数据处理速度,特别适用于高并发和大数据量的场景。 ... [详细]
  • 在 CentOS 6.4 上安装 QT5 并启动 Qt Creator 时,可能会遇到缺少 GLIBCXX_3.4.15 的问题。这是由于系统中的 libstdc++.so.6 版本过低。本文将详细介绍如何通过更新 GCC 版本来解决这一问题。 ... [详细]
  • 如果应用程序经常播放密集、急促而又短暂的音效(如游戏音效)那么使用MediaPlayer显得有些不太适合了。因为MediaPlayer存在如下缺点:1)延时时间较长,且资源占用率高 ... [详细]
  • 基于iSCSI的SQL Server 2012群集测试(一)SQL群集安装
    一、测试需求介绍与准备公司计划服务器迁移过程计划同时上线SQLServer2012,引入SQLServer2012群集提高高可用性,需要对SQLServ ... [详细]
  • 本文介绍了在 Java 编程中遇到的一个常见错误:对象无法转换为 long 类型,并提供了详细的解决方案。 ... [详细]
  • 在Linux系统中,网络配置是至关重要的任务之一。本文详细解析了Firewalld和Netfilter机制,并探讨了iptables的应用。通过使用`ip addr show`命令来查看网卡IP地址(需要安装`iproute`包),当网卡未分配IP地址或处于关闭状态时,可以通过`ip link set`命令进行配置和激活。此外,文章还介绍了如何利用Firewalld和iptables实现网络流量控制和安全策略管理,为系统管理员提供了实用的操作指南。 ... [详细]
  • 本文深入解析了Java 8并发编程中的`AtomicInteger`类,详细探讨了其源码实现和应用场景。`AtomicInteger`通过硬件级别的原子操作,确保了整型变量在多线程环境下的安全性和高效性,避免了传统加锁方式带来的性能开销。文章不仅剖析了`AtomicInteger`的内部机制,还结合实际案例展示了其在并发编程中的优势和使用技巧。 ... [详细]
  • 本文深入探讨了 Git 与 SVN 的高效使用技巧,旨在帮助开发者轻松应对版本控制中的各种挑战。通过详细解析两种工具的核心功能与最佳实践,读者将能够更好地掌握版本管理的精髓,提高开发效率。 ... [详细]
author-avatar
无声胜有剩
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有