std::map 删除/插入无效;静态对象内的成员无效->;好吧,这些都是表象

先说结论:使用单例模式或者静态成员变量时,获取时尽量获取其指针,而非引用。 最近在看《Effective C++》还没看完,不知道他里面有没有这样一条规则,如果没有,我觉得可以加上哈哈。为什么这样,看这样一段代码

class A
{
	...
	B& getB()
	{
		return B
	}
	static B;//假设已经存在B
	...
}

//在其他地方调用
A a;
B& b = a.getB();

上面这种写法,没有任何问题。可如果你手抖了一下,写成了这样

B b = a.getB();

上述这种写法,不会报任何错误,然后你很开心的去操作b,一顿操作猛如虎,可当你在其他地方使用B时,会惊奇的发现,上帝,我之前对B的修改怎么都不见了!!!你郁闷了,电脑坏了吗?但事实时,由于你的手抖,你刚刚复制了一份对象,而这个对象在函数跳出时,被析构了。这个错误真是太过隐蔽了,以至于我找了两天!如果你获取指针,那将没有任何问题。好了到这里,基本就是对这条规则的解释。下面就是我的奇葩之旅,其实没必要看,如果你好奇的话,可以接着看。

事故发生

我做了一个单例类,类中有一个map,这个map里存放的key—value是指针类型(关于此我想说一点,网上有不少帖子说std::map的key只能存放对象,否则会在find()时找不到,对此我想说,不知道他们尝试过没,或者是他们其他的地方写的有错误,这根本就是不对的,在误导大众,对map理解不到位map是一个模板类,存储时并无对象指针之分,当存储对象时,就是把对象复制一份,当存储指针就是把指针复制一份,查找时就是对比指针值是否相同,指针说白了就是十六进制的数既然是数,当然就可以比较,只不过不能比较指针指向的数据而已。需要注意的就是key的类型尽量不要是const char*,关于此网上有很好的解释,可以去看。所以大家可以放心的存放指针类型,有什么问题我们可以共同交流。试想一下,如果key只能存储对象,那效率得多低。)

接着说,然后我就在迭代获取指定的数据,然后调用delete it->second删除。然后重新为 it->second赋值像这样 it->second = new A;然后我在其他函数里调用it->second->…试图访问A的函数,结果就报错了!多次调试发现,it->second的地址在我进行 it->second = new A时改变了,可当我在其他函数调用时,it->second尽竟然仍然指向未赋值之前的地址,然而那个地址的数据我已经删除了,自然就报错了。

漫长思考

这证明了什么,证明了it->second = new A时,it->second并没有被改变。难道map不允许这样操作?,于是上网查,看到的都是非指针类型可以这样操作,指针类型的找不到,于是google,依然一无所获,在仔细想想,他并非是没有改变,而是在另外的函数里失效了。于是又上网查迭代器的失效是怎么回事,都说的是只有进行erase操作之后才失效。可是我并没有。。。此时已经接近零点。唉,算了吧,既然此路不通,那就只能换条路了,先睡吧。觉得可能是电脑的问题,期间反复重新生成,都不行。

几近崩溃

第二天,我想到了,既然删除数据不行,那我就把整个迭代器删除,包括数据,然后重新插入这总行了吧。幻想着马上就解决了,心情很是高兴。还为自己的灵活变通感到骄傲。可现实就是现实,这样也不行,错误还是那个。难道插入操作也不对?奇怪了,于是我又在map里插了将近10条数据,结果一到那个函数,还是啥都没变,原来插得数据都不见了。我想,这个map有问题?于是我又在类里加了另外的map,进行同样的操作,结果令我大跌眼镜,同样的问题在这个新建的对象上出现了。难道是key-value类型的问题?于是我用最简单的std::map<int*, int*>c测试,问题依旧,这都不行,那我用in类型的成员变量总行了吧。结果只要进了那个函数int类型的值竟然变成了0!!!我想,一定是我电脑中毒了!!!!

出现转机

连int类型的值都保存不了,大哥,我这个可是静态的啊,你凭啥给我变成0???难道静态的对象,必须成员也得是静态的才行,于是我把成员换成静态的,确实,没有问题了,可是一旦这个这个结论成立,我脑子中建构的C++知识体系恐将倾覆。不行,不甘心,于是上网求证,看关于静态对象问题,结果东西少之又少,大多都讲得是静态成员变量的初始化问题。已经耗了几天了,往往这个时候(你遇到的问题网上几乎没有,说明你这个问题非常非常小众,而这个小众的问题与你的代码联系异常紧密。例如逻辑等。在编程时,出错了,千万不要轻易怀疑电脑的问题,以我的经验来看,目前遇到的所有问题,都数次怀疑是电脑问题,结果都被打脸。)就应该回归问题本质,回归基础知识,所谓问题本质,就是思考,什么样的情况下,会出现这样的问题,这就体现出基础知识的重要性。凭借基础知识,推翻所有假设,首先我想到,我的对象是静态的,这意味着他将存在于整个程序运行期间。静态数据,在公共数据存储区,而其成员也直到程序退出才被析构。是不可能出现这种情况的。可是我这个静态数据成员的初始化在getInstace()里,且构造函数不是私有的,所以有没有可能在哪个地方被构造了呢?于是调试看有没有进入构造函数,结果令人失望。再仔细想,这些成员变量,之所以被修改后又回到修改之前,还有一种可能,那就是被析构了。

水落石出

可是,我是静态的怎么可能被析构呢,但是也只有这一种可能了,至少目前看来是能想到的唯一可能。于是,继续调试,终于发现,它竟然进了析构函数。闻所未闻,赶紧跳出来看代码是哪里,最后,我看到了这样一句:、
在这里插入图片描述
这个getInstance()返回的是引用!!!

至此,两天多的谜题终于揭晓,从最初的std::map查到这里,有无数次想砸电脑。但心情平静下来之后,发现,也许最初我老老实实的按大多数人的返回指针不就好了,人家怎么做,你也怎么做不就好了,这也许是对的,但也许不是对的;另外就是基础知识的重要性,这里的重要不是指你知道,能背出来就行,而是要理解并能在纷繁复杂的表象中利用他,坚定信心,抽丝剥茧,最后解决问题。

题外话:原本想快速完成这周任务,不料来了个这问题,收获也有,损失也有,这就是生活,是人生。生活千变万化,我们的心却可以不变,这很难,但若你想优秀,对不起,你必须经历,必须承受,必须不变!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值