boost any类库的使用和内部实现细节
2015-11-03 22:35
417 查看
boost any类库的使用
功能
可以将任何类型值保存到boost::any类中。也可以通过boost::any_cast模板方法来将boost::any类中设置的数据,安全地拿出来。基本小例子
将任何数据保存到any类中
#include <assert.h> #include <boost/any.hpp> #include <string> #include <vector> #include <map> using namespace std; using namespace boost; class Student { public: Student() : age_(25) {} Student(int age) : age_(age) {} int GetAge() const { return age_; } private: int age_; }; int calc_max(int data1, int data2) { return data1 > data2 ? data1 : data2; } int main(int argc, char **argv) { int a[] = {1, 2, 3, 4, 5}; vector<int> iv(a, a + 5); map<string, int> info; int i = 100; info["zs"] = 10; info["ls"] = 5; //======================支持将任何类型通过构造函数来创建any对象====================== // 将基本数据类型保存到any类中 any any1(10); any any2("hello world"); any any3(2.5f); any any4(3.14); any any5(a); any any6(&i); // 将对象保存到any类中 any any7(string("hello world")); any any8(iv); any any9(info); // 将用户自己定义的类型对象保存到any类中 Student stu; any any10(stu); // 可以使用某个现有的any对象来进行拷贝构造 any any11(any9); // ================也可以讲任何类型复制给any对象======== any10 = Student(); any10 = any3; any10 = 1; any10 = &calc_max; any10 = any3; any10 = vector<int>(); //any any12(int()); //千万不能这样写 //any any12(&calc_max); //any12 = any10; return 0; }
怎么样,很吃惊吧,从上面的代码中,我们可以看到,我们可以将基本数值类型(int、double、float、char、各种指针)、标准库中鲜有的模板类对象、用户自己定义的各种类型。
而且any也支持对于自身的拷贝构造和赋值操作。你会发现,通过这种支持。你可以讲保存int数值的any对象赋值给保存字符串的any对象,那么保存字符串的any对象就会变成保存int数值的any对象。你会发现使用any来接收数据的话,就像使用了某种动态语言。对于c++这种静态语言来讲,真的是实在是太太惊艳了。
而且也支持将任何类型的数值或者对象赋值给现有的any对象。也就是说,你不但可以通过构造器来构造保存任意值的any对象,你还可以将已经保存了某种类型值的any对象中值改变成其他类型。真的是太像动态语言了。
下面说一个有趣的问题,也是使用值来构造any的一个注意点
any stu(Student()); //这儿是我想使用一个默认的Student对象来赋值给stu
注意这样写是不行的,为什么呢?因为这样写等价于any stu(Student(*)())。编译器会把它当做一个函数声明。
对于上面的,我们可以通过这样写any stu(Student(25));
或者: Student tmp; any stu(tmp);
从any对象中获取值
/* * app.cpp * * Created on: 2015年11月3日 * Author: TwoFlyLiu */ #include <assert.h> #include <boost/any.hpp> #include <boost/type_index.hpp> #include <string> #include <vector> #include <map> #include <iostream> using namespace std; using namespace boost; template <typename T> struct append_const_to_ptr { typedef const T * type; }; template <typename T> struct append_const_to_ptr<const T> { typedef const T *type; }; // 这个宏的设计意图是为了解决,boost any库以数组构造any对象,所产生的类型衰减问题。 // 经过测试:mingw编译器对于int a[]还是const int a[],最后衰减成的类型都是int const*类型。 // 而对于vc编译器来讲,则比较正常,对于int a[],会衰减成int *,对于const int a[],则会衰减成int const * // 这个宏的目的,就是设置真正的衰减后的类型,这样在any_cast中,就不会发生类型转换的错误 #if defined(__GNUC__) #define DECAY_ARRAY_TYPE(value_type) append_const_to_ptr<value_type>::type #elif defined(_MSC_VER) #define DECAY_ARRAY_TYPE(value_type) value_type * #endif int main(int argc, char **argv) { int a[5] = {1, 2, 3, 4, 5}; vector<int> iv(a, a + 5); map<string, int> info; int i = 100; info["zs"] = 10; info["ls"] = 5; any object_or_val(i); // 通过boost::any_cast来从any中获取任何类型的值。 // 有两大种any_cast重载函数, // 一种是: // template <typename ValueType> ValueType &any_cast(any &),可能会抛出bad_any_cast异常,当转换类型和实际类型不一致时候,会抛出异常 // template <typename ValueType> ValueType &any_cast(any *) assert(100 == *any_cast<int>(&object_or_val)); try { assert(100 == any_cast<const int>(object_or_val)); } catch(boost::bad_any_cast &e) { cout << "error" << endl; } object_or_val = a; //这儿需要注意,对于数组来讲,当他传进去时,内部类型会衰减成指针类型 cout << typeindex::type_index(object_or_val.type()) << endl; // DECAY_ARRAY_TYPE自己定义的,用来解决vc编译器和mingw编译器衰减规则不同问题。 // 具体问题,看上面这个宏的定义 assert(a[0] == **any_cast<DECAY_ARRAY_TYPE(int)>(&object_or_val)); try { assert(a == any_cast<DECAY_ARRAY_TYPE(int)>(object_or_val)); } catch(boost::bad_any_cast &) { cout << "error" << endl; } object_or_val = iv; assert(iv == *any_cast<vector<int> >(&object_or_val)); try { any_cast<vector<int> >(object_or_val); } catch(boost::bad_any_cast &) { cout << "error" << endl; } object_or_val = info; assert((info == *any_cast<map<string, int> >(&object_or_val))); try { any_cast<map<string, int> >(object_or_val); // 使用指针作为参数,转换不成功会返回空指针 assert(0 == any_cast<string>(&object_or_val)); // 使用引用作为参数,转换不成功则会抛出boost::bad_any_cast异常 // 这儿因为类型不一致,所以内部会抛出异常(有意的,为了说明档转换成的类型和内部类型不一致的时候,会抛出异常) // any_cast<string>(object_or_val); } catch(boost::bad_any_cast &) { cout << "Error" << endl; } // 其实还有unsafe_any_cast,非常不推荐使用它,强烈抵制啊 object_or_val = i; cout << *unsafe_bad_cast<int>(&object_or_val) << endl; return 0; }
从上面的代码可以看出。从any对象中取出实际数据的模板函数式any_cast。这个函数4个重载。
template <typename ValueType> ValueType *any_cast(any *) BOOST_NOEXCEPT
template <typename ValueType> ValueType *any_cast(const any *) BOOST_NOEXCEPT
template <typename ValueType> ValueType &any_cast(any &)
template <typename ValueType> ValueType &any_cast(const any &)
template <typename ValueType> ValueType *unsafe_any_cast(any *) BOOST_NOEXCEPT
template <typename ValueType> ValueType *unsafe_any_cast(const any *) BOOST_NOEXCEPT
这个6个重载函数前四个方法其实分为两大类,一种,是用指针作为参数和返回值类型。这种事类C的编程风格,使用这种风格的函数,是不会抛出异常的,但是当转换失败的时候会返回空指针。还有一种是以引用作为参数和最终值类型,使用这种事c++编程风格,使用这种函数当要获取的类型和实际类型不符的时候,会抛出bad_any_cast异常。
最后两个是进行不安全转换的,严重不推荐使用它,因为他连对传入的数据是否为空都没有检查,类型也没有检查,直接返回真正的数据。这样非常容易出现运行时错误的。当一定要使用他的时候,一定要保证传入unsafe_any_cast的实际参数不能为空。并且ValueType类型和any对象的真实类型的内存模型要保证兼容,这样才不会有运行错误。
使用any和any_cast有一个小的注意点
当any对象保存数组的时候,其实在any内部保存的类型是数组的衰减类型。但是对于不同的编译器,any内部的实现对于数组衰减的具体类型也不相同。具体:
编译器 | 原来数组类型 | 衰减后类型 |
---|---|---|
vc++ | int a[5] | int * |
vc++ | const int a[5] | int const * |
mingw | int a[5] | int const* |
mingw | const int a[5] | int const* |
int const *。我在上面的小样例中给出了一个
DECAY_ARRAY_TYPE宏,他可以解决解决两个编译器之间的差异性,只是对于其他编译器,我没有进行测试,我不知道他们的衰变规则。
访问/修改any对象的内部状态
#include <boost/any.hpp> #include <iostream> #include <assert.h> using namespace std; using namespace boost; int main(int argc, char **argv) { int data = 10; any value; assert(value.empty()); //empty()方法用来返回内部是否保存数据 value = data; assert(!value.empty()); //很明显当内部保存数据的时候,empty方法就不返回true了 // type方法用来返回内部类型信息boost::typeindex::type_info类型,其实这个类型是boost::typeindex::type_index类,内部数据类型。具体还请看boost TypeIndex库,可以看前面写的博客,也可以看官方文档 assert(typeindex::type_id<int>() == value.type()); // 输出any对象内部具体的数据类型 cout << "value type : " << typeindex::type_index(value.type()) << endl; // 清除内部保存的数据,这样它又变成空了 value.clear(); assert(value.empty()); return 0; }
any对象主要有如下三个访问/修改内部状态的方法。
方法名称 | 功能 | 小程序片段 |
---|---|---|
bool empty() | 用来检测内部是否有数据 | any a; assert(a.empty()); |
void clear() | 用来清除内部保存的数据,然后他会变成空的any对象 | any a(5); a.clear(); assert(a.empty()); |
boost::typeindex::type_info type() | 用来保存内部真正的类型信息 | any a(5); assert(a.type() == boost::typeindex::type_id<int>()); |
有个小技巧
当你不确定某种类型在any对象中的具体类型时,你通过any对象的type方法来获取类型信息,然后通过此类型信息来构建boost::typeindex::type_index对象,这个对象支持输出流操作,他会输出便于人阅读的名称。
比如:
any a(10);
boost::typeindex::type_index type(a.type());
cout << type << endl;
他会输出int,这是个非常实用的小技巧
any类的swap方法
因为这个方法类似于stl中的swap方法,所以只提供一个小样例:#include <boost/any.hpp> #include <iostream> #include <string> #include <assert.h> using namespace boost; using namespace std; int main(int argc, char **argv) { string hello("hello world"); int data = 20; any val1(hello); any val2(data); assert(typeindex::type_id<string>() == val1.type()); assert(typeindex::type_id<int>() == val2.type()); val1.swap(val2); assert(typeindex::type_id<string>() == val2.type()); assert(typeindex::type_id<int>() == val1.type()); swap(val1, val2); //也支持全局的swap方法 assert(typeindex::type_id<string>() == val1.type()); assert(typeindex::type_id<int>() == val2.type()); return 0; }
boost any类库的实现
这个类库主要包含两部分,一部分是any类的实现,另一部分时any_cast模板方法的实现。any类的实现
any类的实现,包含成员数据和成员方法。成员方法在上面介绍这个类的使用的时候已经非常清楚了。主要是构造器,赋值运算符,和三个访问/修改内部状态的方法。内部成员其实也简单,如果你看源码的话,你会发现他只有一个place_holder类型的指针。place_holder类的实现
namespace boost{ class any { ... // 我认为这儿placeholder就是一个抽象类(这儿类似于java中的接口概念)。通过它,我们可以获取内部数据类型,和拷贝自己信息到一个新对象中 class placeholder { public: virtual ~placeholder() {} public: //获取内部数据类型 virtual const boost::typeinde::typ 1023f e_info & type() const BOOST_NOEXCEPT =0; //原型方法,用于拷贝自身对象信息到新的placeholder对象中 virtual placeholder * clone() const =0; }; ... }; }
placeholder类是一个抽象类,只能通过它来获取内部类型信息和提供拷贝自身的能力。
他有真正的实现是holder类,他才是真正的用来保存数据类的地方。
holder类的实现
namespace boost{ class any { ... template <typename ValueType> class holder : public placeholder { public: // 通过指定类型数据来构造holder对象 holder(const ValueType &value) : held(value){} // 如果支持右值引用,则利用右值引用提高程序性能 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES holder(ValueType&& value) : held(static_cast< ValueType&& >(value)) { } #endif public: // 实现placeholder中的抽象方法 virtual const boost::typeinde::type_info & type() const BOOST_NOEXCEPT { return boost::typeindex::type_id<ValueType>().type_info(); } //原型方法,用于拷贝自身对象信息到新的placeholder对象中 virtual placeholder * clone() const { return new holder(held); } public: ValueType held; // 真正内部保存的值 private: // 当holder构造好的时候,不支持在关边内部的值。其实这儿实现比较无关主要,如果你禁用它的话,那么你也要拷贝右值引用的情况 holder & operator=(const holder &); //下面这个方法是我后添加的,主要是为了和上面成对 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES holder & operator=(holder &&); #endif }; ... }; }
holder类是一个模板类,他实现类抽象类placeholder中的抽象方法。因为他是个模板方法,所以他可以用来保存任何类型的值。
any类的几种构造器和析构器实现
namespace boost { class any { public: // 空的话,则不保存任何数据 any() BOOST_NOEXCEPT : content(0) {} // 利用placeholder的clone方法,就可以实现内部数据的拷贝了 any(const any &other) : content(other.content ? other.content->clone() : 0) {} // 一个关键构造,模板构造器,因为他any类才可以使用任何类型值来构造 // 通过这个构造器也可以看出, // 不管ValueType是否有cv修饰,最终保存到holder类内部的类型总是不含有cv的 // 如果ValueType是数据的话,他也会通过decay type_traits类衰减成指针的。只是这儿还是会有上面提到的,对于不同编译器的衰减类型不同问题,关键还是看上面any类的使用部分。 template <typename ValueType> any(const ValueType & value) : content(new holder<typename remove_cv<typename decay<const ValueType>::type>::type>(value)) {} //如果支持右值引用的话,则提供移动构造来优化程序性能 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES // 移动构造器 any(any&& other) BOOST_NOEXCEPT : content(other.content) { other.content = 0; } // 如果ValueType不是any&引用类型,并且也不是常量的话,才会将value之完美转发到holder的held成员中。 // 这儿有意思的是disable_if这个模板类,利用它可以对ValueType的具体类型就行限制 template<typename ValueType> any(ValueType&& value , typename boost::disable_if<boost::is_same<any&, ValueType> >::type* = 0 // disable if value has type `any&` , typename boost::disable_if<boost::is_const<ValueType> >::type* = 0) // disable if value has type `const ValueType&&` : content(new holder< typename decay<ValueType>::type >(static_cast<ValueType&&>(value))) { } #endif // 析构器,删除content,这样不会发生内存泄露问题 ~any() { delete content; } ... private: placeholder *content; //用来表示真实的内部数据 }; }
从上面的构造器我们可以看到,
1. any类支持空构造器,这个时候他的数据成员content为空,
2. 支持拷贝构造器,对于内部数据content也利用这个数据的clone方法进行拷贝。
3. 还提供了一个模板构造器,利用它我们可以利用任何类型对象构造any对象。
4. 而且如果编译器支持c++11的右值引用的话,我们还提供了移动构造器,和对任意右值引用类型进行完美转发。这样就能大大优化程序性能。
并且通过第3点的实现部分,我们可以看到,在holder类中的数据类型是不带有cvr修饰的(cv是通过remove_cv去除的,r在decay中也会将他去除)。如果模板参数是数组的话,那么他也会通过decay模板类将数组衰减成指针类型。这儿的衰减规则,可能还会出现不同编译器,出现规则不同的问题。如果要修复这个问题,可能还要看decay模板类的实现问题。当然也不一定要深究,只要使用我上面写的DECAY_ARRAY_TYPE宏,可以解决vc++和mingw他们在这儿出现衰减规则不同的问题。简而言之,如果模板类型是带有cvr修饰的话,最终内部数据类型是不带cvr特性的。如果模板参数是数组类型,则最终内部数据类型是数组衰变后的指针类型。
any类重载的赋值运算符
namespace boost { class any { public: // 交换内部的数据成员。这个方法在重载==运算符中被大量使用 any & swap(any & rhs) BOOST_NOEXCEPT { std::swap(content, rhs.content); return *this; } // 不支持右值引用的情况 #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES // 这儿为了避免发生资源泄露,使用了swap方法 // 细节: // 1. 利用rhs构建了一个临时的any对象 // 2. 然后将临时any对象和*this对象进行交换。这样临时any对象保存*this中的数据,而*this则保存原来临时any对象利用rhs构建的数据 // 3. 当临时any对象超出作用域的时候,析构函数会被调用,内部数据content会被删除,这样原来的内部数据就会被删除调用这样就不会发生资源泄露问题 template <typename ValueType> any & operator==(const ValueType &rhs) { any(rhs).swap(*this); return *this; } // 有意使用值,不适用引用 // 因为如果使用引用的话,还要在内部构建一个临时变量,然后进行交换,还不如让编译器帮我们构建临时变量 any & operator==(any rhs) { //rhs.swap(*this); any(rhs).swap(*this); //这儿是原来boost库中的实现,不管我认为应该使用上面的写法,这样少构造一个any对象 return *this; } // 支持右值情况,则利用右值进行优化 #else any & operator==(const any & rhs) { any(rhs).swap(*this); return *this; } // 这儿因为右值引用他是不会发生超出作用域析构的,所以新建了一个临时any对象来析构右值引用中的值,这儿是个小技巧 any & operator==(any &&rhs) { rhs.swap(*this); any().swap(rhs); return *this; } // 直接利用任意右值引用数值来优化any对象的构造 // 这儿仍然是通过static_cast<ValueType&&>来实现完美转发 // 仍然利用swap方法和临时变量来保证原来的any对象内部的资源会被释放掉 template <typename ValueType> any & operator==(const ValueType &value) { // 这儿static_cast<ValueType&&>(value)等价于forward<ValueType>(value) any(static_cast<ValueType&&>(value)).swap(*this); return *this; } #endif ... }; }
正如上面所见,any类重载了对于any对象的赋值运算符和重载了对于任意类型的赋值运算符。因为这两个重载,所以any对象支持将任意any对象赋值给任意any对象,不管他们的内部数据是否一致。也支持将任意类型赋值给any对象,并且原来any对象的内部数据也会被完全释放掉。
any类访问/修改内部状态方法
namespace boost { class any { public: ... // 原来获取内部数据是否为空 bool empty() const BOOST_NOEXCEPT { return !content; } // 删除内部数据,仍然利用,临时变量和swap方法 // 这种手段可以保证资源能被安全释放掉 void clear() BOOST_NOEXCEPT { any().swap(*this); } // 用来获取内部保存的数据类型信息 // 如果内部没有数据的话,则保存的是void的数据类型,如果有数据的话 //则直接调用placeholder接口提供的type方法 const boost::typeindex::type_info & type() const BOOST_NOEXCEPT { return content ? content->type() : boost::typeindex::type<void>().type_info(); } ... }; }
上面的三种方法,在源码中都非常简单,这儿就不进行重复说明了。
全局swap方法
很简单,看源码了:namespace boost { inline void swap(any & lhs, any & rhs) BOOST_NOEXCEPT { lhs.swap(rhs); } }
any_cast模板方法的实现
如果编译器支持类的友元模板函数的话,那么下面的两个模板方法:template<typename ValueType>ValueType * any_cast(any *) BOOST_NOEXCEPT和
template<typename ValueType>ValueType * any_cast(any *) BOOST_NOEXCEPT都是any类的友元类。
具体源码表现在any类定义中:
namespace boost { class any { // 如果支持成员友元模板 #ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS private: // representation template<typename ValueType> friend ValueType * any_cast(any *) BOOST_NOEXCEPT; template<typename ValueType> friend ValueType * unsafe_any_cast(any *) BOOST_NOEXCEPT; #endif }; }
小补充
其实placeholder类和holder类还有一点没有说,如果编译器支持成员友元模板的话,则他们的访问限制为private,否则为public。源码也很简单和上面类似,自己看找源码吧。
any_cast指针版本的实现源码如下:
namespace boost{ //因为是友元,或者holder和placeholder设置为public,所以他能访问到any中的内部数据和内部定义的两个lz // 功能就是讲operand转换为ValueType值,以指针形式返回 // 细节: // 1. 检测operand是否为空,如果为空,则直接返回0 // 2. 检测ValueType不带cv修饰的类型是否和any对象内部数据类型一致, // 只有一致的时候,才会将真正的数据进行返回,否则返回0 template<typename ValueType> ValueType * any_cast(any * operand) BOOST_NOEXCEPT { // typename remove_cv<ValueType>::type获取的是不带cv修饰的类型 return operand && operand->type() == boost::typeindex::type_id<ValueType>() ? &static_cast<any::holder<BOOST_DEDUCED_TYPENAME remove_cv<ValueType>::type> *>(operand->content)->held : 0; } // 内部就是调用非const版本,所以功能和上面的方法完全一致,详情,看上面的那个方法 template<typename ValueType> inline const ValueType * any_cast(const any * operand) BOOST_NOEXCEPT { return any_cast<ValueType>(const_cast<any *>(operand)); } }
在这儿我要介绍一下bad_any_cast异常类,因为他在any_cast的对于引用的版本中被用到。源码如下:
namespace boost{ //一个常量类,当rtti关闭的时候,继承std::bad_cast异常类 //当rtti启用的时候,继承std::exception异常 class bad_any_cast: #ifdef BOOST_NO_RTTI public std::bad_cast #else public std::exception #endif { public: virtual const char * what() const BOOST_NOEXCEPT_OR_NOTHROW { return "boost::bad_any_cast: " "failed conversion using boost::any_cast"; } };
很简单吧,就是一个异常类。
any_cast的引用版本源码:
namespace boost { // 他是any_cast引用版本的核心实现部分,其他版本都是调用它 // 他的内部实现依赖于any_cast的指针版本 // 细节: // 1. 利用any_cast的指针版本来指针返回值 // 2. 如果获取到的返回值为0的话,则抛出bad_any_cast异常 // 3. 最后将返回值的引用类型返回 template<typename ValueType> ValueType any_cast(any & operand) { typedef BOOST_DEDUCED_TYPENAME remove_reference<ValueType>::type nonref; // 去除ValueType的引用修饰 // 调用的是any_cast的指针版本 nonref * result = any_cast<nonref>(&operand); // 值为空的话,则抛出异常 if(!result) boost::throw_exception(bad_any_cast()); // Attempt to avoid construction of a temporary object in cases when // `ValueType` is not a reference. Example: // `static_cast<std::string>(*result);` // which is equal to `std::string(*result);` typedef BOOST_DEDUCED_TYPENAME boost::mpl::if_< boost::is_reference<ValueType>, ValueType, BOOST_DEDUCED_TYPENAME boost::add_reference<ValueType>::type >::type ref_type; // ValueType的引用值 // 用来避免构造多余的临时变量 return static_cast<ref_type>(*result); } // 调用上面的版本 // 他在内部首先把引用修饰给去除掉了,然后调用上面的版本 // 所以他的行为和上面版本的行为基本一致,详细看上面的那个方法 template<typename ValueType> inline ValueType any_cast(const any & operand) { typedef BOOST_DEDUCED_TYPENAME remove_reference<ValueType>::type nonref; return any_cast<const nonref &>(const_cast<any &>(operand)); } // 获取右值any对象的数据,因为any对象是右值,其内部数据也是右值 // 而右值只有右值和const引用能够接受,所以内部首先有个static_assert // 用来保证ValueType是右值引用,或者常量引用 // 内部调用的是any_cast的引用版本,所以他也可能会抛出异常,具体看ValueType & any_cast(any &operand)这个版本方法 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES template<typename ValueType> inline ValueType any_cast(any&& operand) { BOOST_STATIC_ASSERT_MSG( boost::is_rvalue_reference<ValueType&&>::value /*true if ValueType is rvalue or just a value*/ || boost::is_const< typename boost::remove_reference<ValueType>::type >::value, "boost::any_cast shall not be used for getting nonconst references to temporary objects" ); return any_cast<ValueType>(operand); } #endif }
对于any_cast方法进行简单小结一下:
首先,any_cast的指针版本和引用版本他们都能实现安全转换,当operand为0,或者转换类型和实际类型不一致的时候,指针版本返回0,引用版本抛出boost::bad_any_cast异常。 any_cast支持包括常量和非常常量的真正和引用版本。也就是说他们可以接收非const类型,可以接收const类型,支持比较全。
unsafe_any_cast的实现如下源码:
namespace boost { // 不检查operand是否为空,类型是否一致,直接访问内部数据,可能会造成严重错误,用时要小心。不然让operand位空,或者类型不一致 template<typename ValueType> inline ValueType * unsafe_any_cast(any * operand) BOOST_NOEXCEPT { return &static_cast<any::holder<ValueType> *>(operand->content)->held; } //调用的是上面版本,详情见上面 template<typename ValueType> inline const ValueType * unsafe_any_cast(const any * operand) BOOST_NOEXCEPT { return unsafe_any_cast<ValueType>(const_cast<any *>(operand)); } }
对unsafe_any_cast总结一下
正如他们名称一样,他们是执行的操作时不安全转换。他们不会检测operand是否为空,要转换成的类型是否和any对象一致。使用的时候有时会引起严重错误的。所以使用的时候你要保证:
operand不能为空
ValueType和any对象内部类型要一致,或者内存模型至少要兼容。
总结
我首先介绍了any类库的基本使用,然后调用了any类库的实现细节。any在boost库中的源码文件为:boost/any.hpp。使用any类库注意点:
1. 不能使用某个类的默认构造函数来构造any对象,比如
any a(int()),原因见上面使用部分描述。
2. 使用数组来构造any对象时,注意实际类型会帅变成指针类型。并且不同编译器可能衰变规则也不一样,规则见上面
3. 对于any对象的内部数据中的真实类型包不包含cvr修饰的
4. 获取值时候,可以使用any_cast方法,可以使用指针版本,则返回的是指针值,如果失败的会则会返回空指针。也可以使用引用版本,如果失败则会抛出boost::bad_any_cast异常
5. boost any类库还提供了unsafe_bad_cast版本,看他的实现,个人感觉也太恶心了吧。使用不当的话,会出现运行时错误,强烈抵制使用它。
相关文章推荐
- boost相关小知识(长期顶置更新)
- C++单元测试:boost.test
- boost asio学习笔记 [1] - 同步通讯
- boost_asio学习笔记[2] - 客户端异步通讯
- boost::flat_map性能测试
- Ubuntu下如何安装boost?
- How to get a boost::shared_ptr from this
- boost 库 enable_shared_from_this 实现原理分析
- boost bind使用指南
- 使用boost进行CRC64计算
- [网络开发]boost::asio简介
- Windows下如何编译使用boost?
- Boost库学习(0)
- Boost库学习(1)log和unittest
- Boost库学习(2)thread 1
- Boost库学习(3)thread 2
- Boost库学习(4)thread 3
- Boost库学习(6)filesystem
- Boost库学习(7)regex
- Boost库学习(8)log