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

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

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

std::any

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

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

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

非成員 any_cast 函數(shù)提供對(duì)所含對(duì)象的類(lèi)型安全訪(fǎng)問(wèn)。

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

Any的基本原理

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

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

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

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

Any類(lèi)

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

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

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

接下來(lái)實(shí)現(xiàn)AnyHelper的構(gòu)造函數(shù)(第一個(gè)是就地構(gòu)造,直接通過(guò)參數(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類(lèi)的構(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>如果類(lèi)型不匹配,后面獲取數(shù)據(jù)時(shí)就會(huì)拋出異常!

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

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

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

賦值運(yùn)算符

賦值運(yùn)算符和構(gòu)造函數(shù)基本一樣,需要注意的是delete原來(lái)的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;
}

其他賦值類(lèi)函數(shù)

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

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

另外,為了優(yōu)化性能,并且支持一些不可移動(dòng)和拷貝的類(lèi)型,我們添加就地構(gòu)造函數(shù),可以直接通過(guò)參數(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類(lèi)就可以存儲(chǔ)數(shù)據(jù)了。

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

對(duì)一個(gè)實(shí)用的Any類(lèi)來(lái)說(shuō),獲取數(shù)據(jù)也是必不可少的,實(shí)現(xiàn)獲取數(shù)據(jù)即將Any轉(zhuǎn)換為其他類(lèi)型。對(duì)std::any來(lái)說(shuō),有std::any_cast函數(shù)來(lái)實(shí)現(xiàn)這一轉(zhuǎn)換,我們也寫(xiě)一個(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*類(lèi)型的data轉(zhuǎn)換為相應(yīng)的AnyHelper子類(lèi)。dynamic_cast是向下轉(zhuǎn)換的操作符,也支持運(yùn)行時(shí)多態(tài),如果轉(zhuǎn)換失敗會(huì)返回空指針。

獲取Any信息

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

獲取類(lèi)型的type_info

我們前面說(shuō)過(guò),在我們實(shí)現(xiàn)的Any類(lèi)中,只有在AnyHelper類(lèi)內(nèi)部我們才會(huì)知道存儲(chǔ)的類(lèi)型。因此,獲取類(lèi)型必須從AnyHelper類(lèi)下首。類(lèi)似于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類(lèi)的Type就好寫(xiě)了:

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

HasValue

沒(méi)啥好說(shuō)的…

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

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

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

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

附錄:完整代碼

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

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)文章

最新評(píng)論