tinyXml和stl中map使用的一点坑

本文中参考的资料:

http://blog.csdn.net/scythe666/article/details/51718864

http://www.cnblogs.com/lizhanwu/p/4428990.html

1、场景回现

前段时间我在参考了上面两个资料之后简单的用C++实现了一下反射机制,实现后想通过xml文件读入所想要的数据来创建类,但是通过tinyXml读取数据后,在map想通过这个数据来找到我所需要的类,发现我传入的这个参数name确实在我map里有存在,但是经过stl中map自带的find函数后,发现找到的结果是这个map的结尾,也就是说通过这个name我并不能在map中找到我所需要的数据。

以下是出现以上错误的全部代码:

#include<map>
#include<iostream>

#include"xml\tinyxml.h"
using namespace std;


//一个宏定义

#define REGISTER(className)                                             \
    RegisterAction::registerClass(#className,className::create)



class Base {
public:
	Base() {}
	~Base() {}

	// 重写实现
	virtual void m_print() = 0;


};

typedef Base* (*ClassCreateCB)();



class TestFactory {
public:
	Base* GetClassByName(const char* name) {
		map<const char*, ClassCreateCB>::iterator iter;
		iter = n_fMap.find(name);
		if (iter == n_fMap.end()) {
			cout << name << ":没有这个类的构造函数" << endl;
			return NULL;
		}
		else {
			return iter->second();
		}
	}
	//换言之是注册
	void addClass(const char* name, ClassCreateCB fun) {
		n_fMap.insert(std::make_pair(name, fun));
	}
	static TestFactory* getInstance() {
		if(instance==NULL){
			instance = new TestFactory();
		}
		return instance;
	}
private:
	map<const char*, ClassCreateCB>n_fMap;
	static TestFactory* instance;
	//工厂类也是一种单例类
	TestFactory() {};
};

TestFactory* TestFactory::instance = NULL;




class TestA :public Base {
public:
	TestA() {};
	~TestA() {};

	static Base* create() {
		return new TestA;
	}

	virtual void m_print() override{
		cout << "this is TestA" << endl;
	}
};


class TestB :public Base {
public:
	TestB() {};
	~TestB() {};

	static Base* create() {
		return new TestB;
	}


	virtual void m_print() override {
		cout << "this is TestB" << endl;
	}
};
class TestC :public Base {
public:
	TestC() {};
	~TestC() {};

	static Base* create() {
		return new TestC;
	}

	virtual void m_print() override {
		cout << "this is TestC" << endl;
	}
};
class TestD :public Base {
public:
	TestD() {};
	~TestD() {};

	static Base* create() {
		return new TestD;
	}

	virtual void m_print() override {
		cout << "this is TestD" << endl;
	}
};


//工具类
class RegisterAction {
public:
	static RegisterAction* getInstance() {
		if (instance == NULL) {
			instance = new RegisterAction;
		}
		return instance;
	}
	static void registerClass(const char* name, ClassCreateCB fun) {
		TestFactory::getInstance()->addClass(name, fun);
	}

	void registerAll() {
		REGISTER(TestA);
		REGISTER(TestB);
		REGISTER(TestC);
		REGISTER(TestD);
	}

private:
	static RegisterAction* instance;
	RegisterAction() {};
};

RegisterAction* RegisterAction::instance = NULL;

int main() {
	RegisterAction::getInstance()->registerAll();

	const char * path = "class.xml";
	TiXmlDocument doc(path);

	bool flag = doc.LoadFile();
	if (!flag) {
		cout << "check for the error" << endl;
	}

	TiXmlNode* root = doc.FirstChild("plist");
	const char* c_strA = "TestA";
	const char* c_strB = "TestB";
	const char* c_strC = "TestC";
	const char* c_strD = "TestD";

	if (!root) {
		cout << "plist not exist" << endl;
	}
	else {
		TiXmlElement* ele;
		for (TiXmlNode* node = root->FirstChild(); node; node = node->NextSibling()) {
			ele = node->ToElement();
			
			const char* str = (ele->Attribute("className"));
			Base* base = TestFactory::getInstance()->GetClassByName(str);
			if (base == NULL) {
				cout << "不存在" << endl;
			}
			else base->m_print();
		}
	}
	system("pause");
}


2、问题解决:

当时出现这个问题的时候我认为是编码上的问题,各种修改后无果便放到一旁了,今天再一次用到tinyXml的时候发现了一个类似的错误,观察了内存之后,发现tinyXml是先将这个文件全部读入到内存中,然后通过tinyXml来获取所需的数据时,返回出来的数据就是在这个内存块上面的,然后当TiXmlDocument的析构函数被调用时,这个内存区上所存放的所有数据都会被清空!

到这里问题就很明确了,比如说一个在Xml中存放的一个字符串“TestA”,这个字符串所在的内存地址和通过一个const char*所创建出来的字符串“TestA”是不一样的,后者是存储在专门存放文字常量的文字常量区中,而从这里我们可以知道,之前的错误发生有一个原因就是因为stl中的find之间的比较应该是直接通过==操作符来实现,对于一个const char*类型的数据,他们==操作符所比较的是两个数据之间的地址,只有当地址一样时这两个值才会一样,也就因此造成了find函数的失效。

解决方法其实很简单,将map中的const char*换成string就解决了,如下:

map<string, ClassCreateCB>n_fMap;

对于string而言其==所比较的是其内容,会造成这样的原因也就消失了,而且string在创建的时候等于会复制一段这个字符串的内容,也就避免了你创建了一个指向tinyXml存放的字符串后由于内存被收回导致的一些错误。


第一次写文,见谅



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值