欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++ std::any的模擬實(shí)現(xiàn)

 更新時(shí)間:2024年02月03日 15:00:55   作者:[PE]經(jīng)典八炮  
std::any是C++標(biāo)準(zhǔn)庫中的一個(gè)類,std::any對(duì)象可以存儲(chǔ)除單例等特殊情況外的任何類型的數(shù)據(jù),本文主要介紹了C++ std::any的模擬實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下

std::any

std::any是C++標(biāo)準(zhǔn)庫中的一個(gè)類,官網(wǎng)對(duì)它的描述如下:

類 any 描述用于任何可拷貝構(gòu)造類型的單個(gè)值的類型安全容器。

類 any 的對(duì)象存儲(chǔ)任何滿足構(gòu)造函數(shù)要求的類型的一個(gè)實(shí)例或?yàn)榭?,而這被稱為 any 類對(duì)象的狀態(tài)。存儲(chǔ)的實(shí)例被稱作所含對(duì)象。若兩個(gè)狀態(tài)均為空,或均為非空且其所含對(duì)象等價(jià),則兩個(gè)狀態(tài)等價(jià)。

非成員 any_cast 函數(shù)提供對(duì)所含對(duì)象的類型安全訪問。

換句話說,std::any對(duì)象可以存儲(chǔ)任何類型的數(shù)據(jù)(單例等特殊情況除外)。這篇文章來探討一下如何自己實(shí)現(xiàn)一個(gè)Any類。

Any的基本原理

在C++這種強(qiáng)類型語言中,想用一種類型來保存多種類型的數(shù)據(jù),首先想到的就是用父類指針(或引用)來保存子類,實(shí)現(xiàn)運(yùn)行時(shí)多態(tài)。但問題是,我們想要保存任意類型,必須使所有類型都有一個(gè)公共的父類。在某些語言(如Java)中,有一個(gè)Object類,是所有類的父類,因此這種語言中就非常容易實(shí)現(xiàn)。但C++的類型系統(tǒng)相當(dāng)混亂,原生類型沒有父類,STL的類型也沒有一個(gè)公共父類,而自定義類型也不會(huì)自動(dòng)繼承自一個(gè)公共父類,因此直接用父類指針不可行。但是如果我們把模板和繼承結(jié)合一下就可以了,為每一種類型創(chuàng)建一個(gè)對(duì)應(yīng)的模板類,這個(gè)模板類又繼承自一個(gè)父類。核心代碼如下:

class AnyHelperBase
{
};
template<typename T>
class AnyHelper :public AnyHelperBase
{
	T data;
};

這樣我們就可以用AnyHelperBase*類型來存儲(chǔ)任意類型的數(shù)據(jù)了。當(dāng)然,這只是大體思路,還需要具體完善。下面我們將以上述代碼為母體,添加功能。

將數(shù)據(jù)存儲(chǔ)到Any

Any類

在上面的代碼中,如何將數(shù)據(jù)存儲(chǔ)到Any?肯定需要一個(gè)AnyHelperBase*的類型。但考慮到直接操作指針不是很方便,并且std::any使用的時(shí)候并不需要指針,我們應(yīng)該再寫一個(gè)類來維護(hù)AnyHelperBase*

class Any
{
private:
	class AnyHelperBase
	{
	public:
	};
	template<typename T>
	class AnyHelper :public AnyHelperBase
	{
	public:
		T data;
	};
	AnyHelperBase* data;
public:
	
};

構(gòu)造函數(shù)

接下來實(shí)現(xiàn)AnyHelper的構(gòu)造函數(shù)(第一個(gè)是就地構(gòu)造,直接通過參數(shù)構(gòu)造data,后兩個(gè)是拷貝構(gòu)造):

template<typename ...Args>
AnyHelper(Args&&... args) :data(std::forward<Args>(args)...) {}
AnyHelper(const AnyHelper& other) :data(other.data) {}
AnyHelper(const T& value) :data(value) {}

Any類的構(gòu)造函數(shù):

Any() :data(nullptr) {}
template<typename T>
Any(const T& value) : data(new AnyHelper<std::decay_t<T>>(value)) {}
//Any(const Any& other) :data( ??? ) {}
Any(Any&& other) :data(other.data)
{
	other.data = nullptr;
}

注意:std::decay_t<T>的作用是去掉T的const,引用等亂七八糟的屬性,比如std::decay_t<const int&>的結(jié)果是int。例如,我們顯然不希望傳入const intint得到不同的結(jié)果。這一點(diǎn)很重要,因?yàn)?strong>如果類型不匹配,后面獲取數(shù)據(jù)時(shí)就會(huì)拋出異常!

拷貝構(gòu)造的困難和解決方案

在寫拷貝構(gòu)造(上面代碼的第三個(gè)函數(shù))時(shí),我們遇到了問題。由于是深拷貝,我們肯定不能直接復(fù)制指針,而是應(yīng)該再new一個(gè)對(duì)象。但問題是,我們?cè)趺传@取另一個(gè)Any中的類型呢?這個(gè)問題似乎不好解決,因?yàn)?strong>只有在AnyHelper類內(nèi)部我們才會(huì)知道存儲(chǔ)的類型(這句話很重要)。但我們可以變通一下,讓AnyHelper類直接返回一個(gè)自身的拷貝的指針,我們不必關(guān)心他具體是什么類型。當(dāng)然,我們使用的是AnyHelperBase*,所以AnyHelperBase類里必須就得有這個(gè)函數(shù),換句話說,這得是一個(gè)虛函數(shù)。在這里我們又用到了多態(tài)的特性。往AnyHelperBase和AnyHelper中添加Clone函數(shù):

class AnyHelperBase
{
public:
	virtual AnyHelperBase* Clone()const = 0;
};
template<typename T>
class AnyHelper :public AnyHelperBase
{
public:
	T data;
	template<typename ...Args>
	AnyHelper(Args&&... args) :data(std::forward<Args>(args)...) {}
	AnyHelper(const AnyHelper& other) :data(other.data) {}
	AnyHelper(const T& value) :data(value) {}
	virtual AnyHelper* Clone()const
	{
		return new AnyHelper(*this);
	}
};

Any類的拷貝構(gòu)造函數(shù):

Any(const Any& other) :data(other.data->Clone()) {}

賦值運(yùn)算符

賦值運(yùn)算符和構(gòu)造函數(shù)基本一樣,需要注意的是delete原來的data

template<typename T>
Any& operator=(const T& value)
{
	if (data != nullptr)
		delete data;
	data = new AnyHelper<std::decay_t<T>>(value);
	return *this;
}
Any& operator=(const Any& other)
{
	if (data != nullptr)
		delete data;
	data = other.data->Clone();
	return *this;
}
Any& operator=(Any&& other)
{
	if (data != nullptr)
		delete data;
	data = other.data;
	other.data = nullptr;
	return *this;
}

其他賦值類函數(shù)

注意到std::any可以有空值,并且可以設(shè)置為空,我們也寫一個(gè)Reset函數(shù)將Any設(shè)為空。

void Reset()
{
	if (data != nullptr)
		delete data;
	data = nullptr;
}

另外,為了優(yōu)化性能,并且支持一些不可移動(dòng)和拷貝的類型,我們添加就地構(gòu)造函數(shù),可以直接通過參數(shù)構(gòu)造一個(gè)對(duì)象。

template<typename T, typename ...Args>
std::decay_t<T>& Emplace(Args&&... args)
{
	if (data != nullptr)
		delete data;
	auto temp = new AnyHelper<std::decay_t<T>>(std::forward<Args>(args)...);
	data = temp;
	return temp->data;
}

還有一個(gè)簡(jiǎn)單的Swap,直接交換data指針:

void Swap(Any& other)
{
	AnyHelperBase* temp = this->data;
	this->data = other.data;
	other.data = temp;
}

到這里,Any類就可以存儲(chǔ)數(shù)據(jù)了。

從Any獲取數(shù)據(jù):Any轉(zhuǎn)換為其他類型

對(duì)一個(gè)實(shí)用的Any類來說,獲取數(shù)據(jù)也是必不可少的,實(shí)現(xiàn)獲取數(shù)據(jù)即將Any轉(zhuǎn)換為其他類型。對(duì)std::any來說,有std::any_cast函數(shù)來實(shí)現(xiàn)這一轉(zhuǎn)換,我們也寫一個(gè)AnyCast函數(shù)。

template<typename T>
T AnyCast(const Any& any)
{
	auto p = dynamic_cast<Any::AnyHelper<std::decay_t<T>>*>(any.data);
	if (p == nullptr)
		throw std::runtime_error("Bad any cast!");
	return p->data;
}
template<typename T>
T AnyCast(Any& any)
{
	auto p = dynamic_cast<Any::AnyHelper<std::decay_t<T>>*>(any.data);
	if (p == nullptr)
		throw std::runtime_error("Bad any cast!");
	return p->data;
}
template<typename T>
T AnyCast(Any&& any)
{
	auto p = dynamic_cast<Any::AnyHelper<std::decay_t<T>>*>(any.data);
	if (p == nullptr)
		throw std::runtime_error("Bad any cast!");
	return p->data;
}
template<typename T>
const T* AnyCast(const Any* any)
{
	auto p = dynamic_cast<Any::AnyHelper<std::decay_t<T>>*>(any->data);
	if (p == nullptr)
		return nullptr;
	return &p->data;
}
template<typename T>
T* AnyCast(Any* any)
{
	auto p = dynamic_cast<Any::AnyHelper<std::decay_t<T>>*>(any->data);
	if (p == nullptr)
		return nullptr;
	return &p->data;
}

AnyCast一共有5個(gè)重載(和STL中的一致),前三個(gè)是一組,后兩個(gè)是一組。前三個(gè)的特性是轉(zhuǎn)換失敗會(huì)拋出異常,后兩個(gè)接受指針,返回指針,失敗不會(huì)拋異常,而是會(huì)返回空指針。5個(gè)函數(shù)實(shí)現(xiàn)原理都是一樣的,核心就是使用dynamic_cast將AnyHelperBase*類型的data轉(zhuǎn)換為相應(yīng)的AnyHelper子類。dynamic_cast是向下轉(zhuǎn)換的操作符,也支持運(yùn)行時(shí)多態(tài),如果轉(zhuǎn)換失敗會(huì)返回空指針。

獲取Any信息

到現(xiàn)在,一個(gè)Any類的核心功能已經(jīng)全部完成,不過為了模擬std::any,我們還是再添加一些獲取信息的函數(shù)。

獲取類型的type_info

我們前面說過,在我們實(shí)現(xiàn)的Any類中,只有在AnyHelper類內(nèi)部我們才會(huì)知道存儲(chǔ)的類型。因此,獲取類型必須從AnyHelper類下首。類似于Clone,我們?cè)贋锳nyHelperBase和AnyHelper添加一個(gè)虛函數(shù):

class AnyHelperBase
{
public:
	virtual const std::type_info& Type()const = 0;
	virtual AnyHelperBase* Clone()const = 0;
};
template<typename T>
class AnyHelper :public AnyHelperBase
{
public:
	T data;
	//構(gòu)造函數(shù)省略
	//...
	virtual const std::type_info& Type()const
	{
		return typeid(T);
	}
	virtual AnyHelper* Clone()const
	{
		return new AnyHelper(*this);
	}
};

這樣Any類的Type就好寫了:

const std::type_info& Type()const
{
	return data->Type();
}

HasValue

沒啥好說的…

bool HasValue()const
{
	return data != nullptr;
}

析構(gòu)函數(shù)

在這里我提醒一下大家,雖然析構(gòu)函數(shù)很簡(jiǎn)單,但一定不要忘了寫,否則會(huì)引起內(nèi)存泄漏!檢查析構(gòu)函數(shù)是一個(gè)很好的代碼習(xí)慣!

~Any()
{
	if (data != nullptr)
		delete data;
}

附錄:完整代碼

到這里,整個(gè)Any類就完成了。下面是完整代碼:

namespace MyStd
{
	class Any
	{
	private:
		class AnyHelperBase
		{
		public:
			virtual const std::type_info& Type()const = 0;
			virtual AnyHelperBase* Clone()const = 0;
		};
		template<typename T>
		class AnyHelper :public AnyHelperBase
		{
		public:
			T data;
			template<typename ...Args>
			AnyHelper(Args&&... args) :data(std::forward<Args>(args)...) {}
			AnyHelper(const AnyHelper& other) :data(other.data) {}
			AnyHelper(const T& value) :data(value) {}
			virtual const std::type_info& Type()const
			{
				return typeid(T);
			}
			virtual AnyHelper* Clone()const
			{
				return new AnyHelper(*this);
			}
		};
		template<typename T>
		friend T AnyCast(const Any& any);
		template<typename T>
		friend T AnyCast(Any& any);
		template<typename T>
		friend T AnyCast(Any&& any);
		template<typename T>
		friend const T* AnyCast(const Any* any);
		template<typename T>
		friend T* AnyCast(Any* any);
		AnyHelperBase* data;
	public:
		Any() :data(nullptr) {}
		template<typename T>
		Any(const T& value) : data(new AnyHelper<std::decay_t<T>>(value)) {}
		Any(const Any& other) :data(other.data->Clone()) {}
		Any(Any&& other) :data(other.data)
		{
			other.data = nullptr;
		}
		const std::type_info& Type()const
		{
			return data->Type();
		}
		bool HasValue()const
		{
			return data != nullptr;
		}
		void Reset()
		{
			if (data != nullptr)
				delete data;
			data = nullptr;
		}
		template<typename T>
		Any& operator=(const T& value)
		{
			if (data != nullptr)
				delete data;
			data = new AnyHelper<std::decay_t<T>>(value);
			return *this;
		}
		Any& operator=(const Any& other)
		{
			if (data != nullptr)
				delete data;
			data = other.data->Clone();
			return *this;
		}
		Any& operator=(Any&& other)
		{
			if (data != nullptr)
				delete data;
			data = other.data;
			other.data = nullptr;
			return *this;
		}
		void Swap(Any& other)
		{
			AnyHelperBase* temp = this->data;
			this->data = other.data;
			other.data = temp;
		}
		template<typename T, typename ...Args>
		std::decay_t<T>& Emplace(Args&&... args)
		{
			if (data != nullptr)
				delete data;
			auto temp = new AnyHelper<std::decay_t<T>>(std::forward<Args>(args)...);
			data = temp;
			return temp->data;
		}
		~Any()
		{
			if (data != nullptr)
				delete data;
		}
	};

	template<typename T>
	T AnyCast(const Any& any)
	{
		auto p = dynamic_cast<Any::AnyHelper<std::decay_t<T>>*>(any.data);
		if (p == nullptr)
			throw std::runtime_error("Bad any cast!");
		return p->data;
	}
	template<typename T>
	T AnyCast(Any& any)
	{
		auto p = dynamic_cast<Any::AnyHelper<std::decay_t<T>>*>(any.data);
		if (p == nullptr)
			throw std::runtime_error("Bad any cast!");
		return p->data;
	}
	template<typename T>
	T AnyCast(Any&& any)
	{
		auto p = dynamic_cast<Any::AnyHelper<std::decay_t<T>>*>(any.data);
		if (p == nullptr)
			throw std::runtime_error("Bad any cast!");
		return p->data;
	}
	template<typename T>
	const T* AnyCast(const Any* any)
	{
		auto p = dynamic_cast<Any::AnyHelper<std::decay_t<T>>*>(any->data);
		if (p == nullptr)
			return nullptr;
		return &p->data;
	}
	template<typename T>
	T* AnyCast(Any* any)
	{
		auto p = dynamic_cast<Any::AnyHelper<std::decay_t<T>>*>(any->data);
		if (p == nullptr)
			return nullptr;
		return &p->data;
	}
}

到此這篇關(guān)于C++ std::any的模擬實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)C++ std::any內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家! 

相關(guān)文章

  • 2048小游戲C語言實(shí)現(xiàn)代碼

    2048小游戲C語言實(shí)現(xiàn)代碼

    這篇文章主要為大家詳細(xì)介紹了2048小游戲C語言實(shí)現(xiàn)代碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-05-05
  • C語言 基本語法示例講解

    C語言 基本語法示例講解

    本篇文章主要講解C語言 基本語法,這里提供簡(jiǎn)單的示例和代碼來詳細(xì)講解C語言的基本語法,開始學(xué)習(xí)C語言的朋友可以看一下
    2016-08-08
  • GetChar緩存機(jī)制深入剖析

    GetChar緩存機(jī)制深入剖析

    以下是對(duì)GetChar緩存機(jī)制進(jìn)行了詳細(xì)的介紹,需要的朋友可以過來參考下
    2013-09-09
  • C語言直接插入排序算法

    C語言直接插入排序算法

    大家好,本篇文章主要講的是C語言直接插入排序算法,感興趣的同學(xué)趕快來看一看吧,對(duì)你有幫助的話記得收藏一下,方便下次瀏覽
    2022-01-01
  • C語言二叉樹的非遞歸遍歷實(shí)例分析

    C語言二叉樹的非遞歸遍歷實(shí)例分析

    這篇文章主要介紹了C語言二叉樹的非遞歸遍歷,包括了先序遍歷、中序遍歷與后序遍歷,需要的朋友可以參考下
    2014-09-09
  • C++超詳細(xì)實(shí)現(xiàn)二叉樹的遍歷

    C++超詳細(xì)實(shí)現(xiàn)二叉樹的遍歷

    本章將會(huì)詳細(xì)講解二叉樹遍歷的四種方式,分別為前序遍歷、中序遍歷、后續(xù)遍歷和層序遍歷。在學(xué)習(xí)遍歷之前,會(huì)先帶大家回顧一下二叉樹的基本概念
    2022-05-05
  • C語言中求余運(yùn)算符的使用解讀

    C語言中求余運(yùn)算符的使用解讀

    這篇文章主要介紹了C語言中求余運(yùn)算符的使用,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • 重構(gòu)-C++實(shí)現(xiàn)矩陣的簡(jiǎn)單實(shí)例

    重構(gòu)-C++實(shí)現(xiàn)矩陣的簡(jiǎn)單實(shí)例

    下面小編就為大家?guī)硪黄貥?gòu)-C++實(shí)現(xiàn)矩陣的簡(jiǎn)單實(shí)例。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2016-06-06
  • 解析C++編程中的繼承方面的運(yùn)用

    解析C++編程中的繼承方面的運(yùn)用

    這篇文章主要介紹了解析C++編程中的繼承方面的運(yùn)用,是C++入門學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下
    2015-09-09
  • C++中靜態(tài)成員函數(shù)訪問非靜態(tài)成員的實(shí)例

    C++中靜態(tài)成員函數(shù)訪問非靜態(tài)成員的實(shí)例

    這篇文章主要介紹了C++中靜態(tài)成員函數(shù)訪問非靜態(tài)成員的實(shí)例的相關(guān)資料,需要的朋友可以參考下
    2017-07-07

最新評(píng)論