boost::any 类型 实现原理

dacxu 2014-03-23 03:38:14
本人在研究boost::any类型的原理,主要参考Kevlin Henney的一篇名为valued conversions的论文。
下面是代码:

#include <iostream>
#include <string>

class any
{
public:
//Representation and basic construction of a generalized union type.
any(): content(0)
{
}

~any()
{
delete content;
}

const std::type_info &type_info() const
{
return content ? content->type_info() : typeid(void);
}

//INWARD CONVERSIONS
any(const any &other) : content(other.content ? other.content->clone() : 0)
{
}

template<typename value_type>
any(const value_type &value) : content(new holder<value_type>(value))
{
}

any &swap(any &rhs)
{
std::swap(content, rhs.content);
return *this;
}

any &operator=(const any &rhs)
{
return swap(any(rhs));
}

template<typename value_type>
any &operator=(const value_type &rhs)
{
return swap(any(rhs));
}

//OUTWARD CONVERSIONS
operator const void *() const
{
return content;
}

template<typename value_type>
bool copy_to(value_type &value) const
{
const value_type *copyable = to_ptr<value_type>();
if(copyable)
value = *copyable;
return copyable;
}

template<typename value_type>
const value_type *to_ptr() const
{
return type_info() == typeid(value_type)?
&static_cast<holder<value_type> *>(content)->held : 0;
}

private:
class placeholder
{
public:
virtual ~placeholder()
{
}
virtual const std::type_info & type_info() const = 0;
virtual placeholder *clone() const = 0;
};

template<typename value_type>
class holder : public placeholder
{
public:
holder(const value_type &value) : held(value)
{
}

virtual const std::type_info &type_info() const
{
return typeid(value_type);
}

virtual placeholder *clone() const
{
return new holder(held);
}

const value_type held;
};

placeholder *content;
};

template<typename value_type>
value_type any_cast(const any &operand)
{
const value_type *result = operand.to_ptr<value_type>();

//return result ? *result : throw std::bad_cast();
if (result)
return *result;
throw std::bad_cast();
}

int main(int argc, char* argv[])
{
any i_a = 3;
int i_b = any_cast<int>(i_a);
std::cout<<i_a<<"\t"<<i_b<<std::endl;

any s_a = std::string("demo");
std::string s_b = any_cast<std::string>(s_a);
std::cout<<s_a<<"\t"<<s_b<<std::endl;

return 0;
}

具体问题如下:
any_cast函数,如果我采用书中的代码return result ? *result : throw std::bad_cast();会异常,
但如果 采用我的
if (result)
return *result;
throw std::bad_cast();
可以正确运行。但是,这两段代码意义是一样的,是否有大神能帮助分析一下?
编译环境是VS2008, 谢谢
...全文
171 6 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
dacxu 2014-03-25
  • 打赏
  • 举报
回复
引用 2 楼 unituniverse2 的回复:
[quote=引用 楼主 u012702526 的回复:] 本人在研究boost::any类型的原理,主要参考Kevlin Henney的一篇名为valued conversions的论文。 下面是代码:

#include <iostream>
#include <string>

class any
{
public:
	//Representation and basic construction of a generalized union type.
	any(): content(0)
	{
	}

	~any()
	{
		delete content;
	}
	
	const std::type_info &type_info() const
	{
		return content ? content->type_info() : typeid(void);
	}

	//INWARD CONVERSIONS 
	any(const any &other) : content(other.content ? other.content->clone() : 0)
	{
	}

	template<typename value_type>
	any(const value_type &value) : content(new holder<value_type>(value))
	{
	}
	
	any &swap(any &rhs)
	{
		std::swap(content, rhs.content);
		return *this;
	}

	any &operator=(const any &rhs)
	{
		return swap(any(rhs));
	}

	template<typename value_type>
	any &operator=(const value_type &rhs)
	{
		return swap(any(rhs));
	}
	
	//OUTWARD CONVERSIONS
	operator const void *() const
	{
		return content;
	}

	template<typename value_type>
	bool copy_to(value_type &value) const
	{
		const value_type *copyable = to_ptr<value_type>();
		if(copyable)
			value = *copyable;
		return copyable;
	}

	template<typename value_type>
	const value_type *to_ptr() const
	{
		return type_info() == typeid(value_type)? 
			&static_cast<holder<value_type> *>(content)->held : 0;
	}

private:
	class placeholder
	{
	public:
		virtual ~placeholder()
		{
		}
		virtual const std::type_info & type_info() const = 0;
		virtual placeholder *clone() const = 0;
	};

	template<typename value_type>
	class holder : public placeholder
	{
	public:
		holder(const value_type &value)	: held(value)
		{
		}

		virtual const std::type_info &type_info() const
		{
			return typeid(value_type);
		}

		virtual placeholder *clone() const
		{
			return new holder(held);
		}

		const value_type held;
	};

	placeholder *content;
};

template<typename value_type>
value_type any_cast(const any &operand)
{
	const value_type *result = operand.to_ptr<value_type>();
	
	//return result ? *result : throw std::bad_cast();
	if (result)
		return *result;
	throw std::bad_cast();
}

int main(int argc, char* argv[])
{
	any i_a = 3;
	int i_b = any_cast<int>(i_a);	
	std::cout<<i_a<<"\t"<<i_b<<std::endl;
	
	any s_a = std::string("demo");
	std::string s_b = any_cast<std::string>(s_a);
	std::cout<<s_a<<"\t"<<s_b<<std::endl;

	return 0;
}
具体问题如下: any_cast函数,如果我采用书中的代码return result ? *result : throw std::bad_cast();会异常, 但如果 采用我的 if (result) return *result; throw std::bad_cast(); 可以正确运行。但是,这两段代码意义是一样的,是否有大神能帮助分析一下? 编译环境是VS2008, 谢谢
我个人不是很喜欢这个any。原因是再小的类型都会被强制分配在堆里面。。。   实现原理上:首先把静态类型转换成运行时类型。holder就是干这个的。至于为什么可行。。。因为再”动态“的类型在整个C++程序中都是需要提前定义好的才能用来实例化,而不可能真的到了编译时根据外部输入临时生成。这会让你想到什么呢?? ——显然所有的可实例化类型仍然是编译时已知的。   你后面问的问题是这样的:因为?:是运算符。到目前为止除了逗号运算符外所有的运算符都是不考虑边界效应的。就比如经常有人在csdn问的那个未定义行为(i++)+(i++)的结果是什么那样。既然是运算符,x=a?b:c的实际步骤不等同于if(a)x=b;else x=c;而是先生成a、b、c然后再去根据a的值选择b还是c赋值给x。换句话说不论a最终为多少,b和c都是要做实际操作的。我记得之前微软的编译器自己做了扩展说如果a是指针则在空指针的情况下在?:里面为假的情况不去取内容,用来兼容那些非规范的代码。但是这种扩展仍然是没有保证的。标准对这类情况的规定是未定义的结果。 而if语句肯定不存在什么边界效应(线程内环境下)。如果有了那就是编译器的不良设计问题[/quote] 可是在any_cast函数中,result实际上不是空指针啊
dacxu 2014-03-25
  • 打赏
  • 举报
回复
引用 1 楼 taodm 的回复:
别浪费时间在研究高阶模板的实现上。能正确用好any就很好了。 人家可能用C++11标准的编译器的。
这个any的实现 不需要C++ 11的支持, 使用的技术 只包括 C++原生支持的 继承,多态和 函数模板,类模板。如果 你有时间,可以帮我分析 一下,问题比较怪异
unituniverse2 2014-03-25
  • 打赏
  • 举报
回复
引用 4 楼 u012702526 的回复:
可是在any_cast函数中,result实际上不是空指针啊
对了我再强调一下,就像你引用我的那个回答里的时候那样 result ? *result : throw std::bad_cast(); 这个是先执行 result、*result、throw std::bad_cast() 再把这3者做为输入来通过“?:”输出到return。可是当throw std::bad_cast()的时候就已经异常了所以根本执行不到return了,就算是result为真也不行。而if(result) return(*result) else throw std::bad_cast();中只要一开始if那里为真就根本碰不到else后面的throw那里去。
unituniverse2 2014-03-25
  • 打赏
  • 举报
回复
引用 4 楼 u012702526 的回复:
可是在any_cast函数中,result实际上不是空指针啊
不用纠结这些了。你知道?:是运算符就可以了。运算符是不能替代if else的,存在副作用(side-effect)。当务之急是消除代码的未定义行为。
unituniverse2 2014-03-23
  • 打赏
  • 举报
回复
引用 楼主 u012702526 的回复:
本人在研究boost::any类型的原理,主要参考Kevlin Henney的一篇名为valued conversions的论文。 下面是代码:

#include <iostream>
#include <string>

class any
{
public:
	//Representation and basic construction of a generalized union type.
	any(): content(0)
	{
	}

	~any()
	{
		delete content;
	}
	
	const std::type_info &type_info() const
	{
		return content ? content->type_info() : typeid(void);
	}

	//INWARD CONVERSIONS 
	any(const any &other) : content(other.content ? other.content->clone() : 0)
	{
	}

	template<typename value_type>
	any(const value_type &value) : content(new holder<value_type>(value))
	{
	}
	
	any &swap(any &rhs)
	{
		std::swap(content, rhs.content);
		return *this;
	}

	any &operator=(const any &rhs)
	{
		return swap(any(rhs));
	}

	template<typename value_type>
	any &operator=(const value_type &rhs)
	{
		return swap(any(rhs));
	}
	
	//OUTWARD CONVERSIONS
	operator const void *() const
	{
		return content;
	}

	template<typename value_type>
	bool copy_to(value_type &value) const
	{
		const value_type *copyable = to_ptr<value_type>();
		if(copyable)
			value = *copyable;
		return copyable;
	}

	template<typename value_type>
	const value_type *to_ptr() const
	{
		return type_info() == typeid(value_type)? 
			&static_cast<holder<value_type> *>(content)->held : 0;
	}

private:
	class placeholder
	{
	public:
		virtual ~placeholder()
		{
		}
		virtual const std::type_info & type_info() const = 0;
		virtual placeholder *clone() const = 0;
	};

	template<typename value_type>
	class holder : public placeholder
	{
	public:
		holder(const value_type &value)	: held(value)
		{
		}

		virtual const std::type_info &type_info() const
		{
			return typeid(value_type);
		}

		virtual placeholder *clone() const
		{
			return new holder(held);
		}

		const value_type held;
	};

	placeholder *content;
};

template<typename value_type>
value_type any_cast(const any &operand)
{
	const value_type *result = operand.to_ptr<value_type>();
	
	//return result ? *result : throw std::bad_cast();
	if (result)
		return *result;
	throw std::bad_cast();
}

int main(int argc, char* argv[])
{
	any i_a = 3;
	int i_b = any_cast<int>(i_a);	
	std::cout<<i_a<<"\t"<<i_b<<std::endl;
	
	any s_a = std::string("demo");
	std::string s_b = any_cast<std::string>(s_a);
	std::cout<<s_a<<"\t"<<s_b<<std::endl;

	return 0;
}
具体问题如下: any_cast函数,如果我采用书中的代码return result ? *result : throw std::bad_cast();会异常, 但如果 采用我的 if (result) return *result; throw std::bad_cast(); 可以正确运行。但是,这两段代码意义是一样的,是否有大神能帮助分析一下? 编译环境是VS2008, 谢谢
我个人不是很喜欢这个any。原因是再小的类型都会被强制分配在堆里面。。。   实现原理上:首先把静态类型转换成运行时类型。holder就是干这个的。至于为什么可行。。。因为再”动态“的类型在整个C++程序中都是需要提前定义好的才能用来实例化,而不可能真的到了编译时根据外部输入临时生成。这会让你想到什么呢?? ——显然所有的可实例化类型仍然是编译时已知的。   你后面问的问题是这样的:因为?:是运算符。到目前为止除了逗号运算符外所有的运算符都是不考虑边界效应的。就比如经常有人在csdn问的那个未定义行为(i++)+(i++)的结果是什么那样。既然是运算符,x=a?b:c的实际步骤不等同于if(a)x=b;else x=c;而是先生成a、b、c然后再去根据a的值选择b还是c赋值给x。换句话说不论a最终为多少,b和c都是要做实际操作的。我记得之前微软的编译器自己做了扩展说如果a是指针则在空指针的情况下在?:里面为假的情况不去取内容,用来兼容那些非规范的代码。但是这种扩展仍然是没有保证的。标准对这类情况的规定是未定义的结果。 而if语句肯定不存在什么边界效应(线程内环境下)。如果有了那就是编译器的不良设计问题
taodm 2014-03-23
  • 打赏
  • 举报
回复
别浪费时间在研究高阶模板的实现上。能正确用好any就很好了。 人家可能用C++11标准的编译器的。

65,187

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧