1
gamingcat1234 2015-02-27 20:00:49 +08:00
|
2
raincious OP @gamingcat1234
感谢,貌似这个数据结构确实不太好,但是不知道怎么实现类似的,于是就糟弄了一把。 但,我想知道的是如何防止这个Stack overflow的问题。关键是在我不知道为什么会有那个Magic number 338在。 |
3
gamingcat1234 2015-02-27 20:42:34 +08:00 1
map <wstring, ContainerStructEnitiy*> SubItems;
然后用new和delete自己分配内存 |
4
sumhat 2015-02-27 20:48:17 +08:00 1
取决于你的 stack 大小和结构体的大小,你可以在 VS 里调大 stack size,然后数值就不是 338 了。
|
5
raincious OP |
7
yangff 2015-02-27 21:15:32 +08:00
linux gcc 4.9.2 20150204 复现不能.
|
8
raincious OP |
9
yangff 2015-02-27 21:22:24 +08:00 1
是这样的,你分配在哪里都没有用.
你前面的代码都没有问题, 思路也没有问题. 但是结束的时候, stl会尝试析构ContainerStructEnitiy. 这肯定是要的..那么问题来了, stl会递归的析构ContainerStructEnitiy下面的各种对象, 比如那个map, map析构的时候又会递归的析构更下面的ContainerStructEnitiy,如此往复, 最后这个析构就把栈炸了. |
10
yangff 2015-02-27 21:25:14 +08:00 1
唯一的办法就是...用指针. 然后手动维护对象生命周期.
不难发现,就算用智能指针也都会有析构的时候爆栈的问题...所以只能手动维护了.. |
11
raincious OP @yangff
嗯,这解释了为什么会在释放的时候出问题。 事实上之前我也尝试过用ContainerStructEnitiy*以及new和delete构建相同的功能(只是ContainerStructEnitiy变成了Class,有自己的析构来释放自己SubItems里的对象),然后发现只要我不叫delete,就不会出现问题(虽然这样真的有问题)。 太悲剧了,请问有办法解决这个问题么?还是我只能放弃这个结构了? |
12
yangff 2015-02-27 21:32:36 +08:00 1
@raincious
ContainerStructEnitiy 改成ContainerStructEnitiy*, 然后把所有的ContainerStructEnitiy*放在pool里面存起来手动delete 一.个.一.个.的delete. |
13
Cee 2015-02-27 21:41:07 +08:00 1
yangff 說的對,用指針維護即可。
還有不是「阀(fa)值」,是「阈(yu)值」。 |
15
1423 2015-02-27 21:57:08 +08:00 1
#include <iostream>
#include <map> using namespace std; struct ContainerStructEnitiy { wstring Name; map <wstring, ContainerStructEnitiy> * pSubItems; }; int main() { int loop = 102000; ContainerStructEnitiy test; ContainerStructEnitiy *ptest = &test; while (loop-- >= 0) { ptest->pSubItems = new map <wstring, ContainerStructEnitiy>; (*(ptest->pSubItems))[to_wstring(loop)].Name = L"blablabla"; ptest = &(*(ptest->pSubItems))[to_wstring(loop)]; cout << loop; } return 0; } 这样行 C++ 好久没用了,凑活看 刚才还没上面的回复。。看来人还是很多的 |
16
raincious OP @1423
感谢。但是不太理解呢。 是说在时候手动清理内存么?因为我看到了new map,测试之后发现函数运行完成返回后内存并没有释放,估计肯定还在堆里。 然后为了偷懒我把代码改成了这样,结果Stack overflow(嗯,就是又造成了我之前的问题): https://gist.github.com/raincious/0f8b527de148e503bd03 可能我没理解对。 难道要完全手动管理么?就是new出map的那些地址也要单独保存下什么的然后在最后一起释放? |
17
yangff 2015-02-27 23:31:00 +08:00 1
@raincious
就是说 class ContainerStructEnitiy { public: wstring Name; map <wstring, ContainerStructEnitiy[*]<<<<---这里要用指针> (*)<<<<<<---这里不用指针没问题pSubItems; ContainerStructEnitiy(); ~ContainerStructEnitiy(); }; 这里的问题在于, 析构ContainerStructEnitiy的时候会析构里面的map, 而map会析构他包含的所有元素,也就是那一堆ContainerStructEnitiy, 这个过程是递归进行的, 因此会造成栈溢出. 不管你是用delete还是c++自己析构, 都会导致这个问题. 解决的办法在于把map对ContainerStructEnitiy的直接管理改成对ContainerStructEnitiy*也就是指针的管理,这样c++在析构map,只会释放保存ContainerStructEnitiy*的内存, 而不会进一步析构他所包含的ContainerStructEnitiy, 然后, 你手动记下所有的ContainerStructEnitiy*, 然后自己把他们delete掉, 就没有问题了. |
18
gamingcat1234 2015-02-27 23:47:46 +08:00 1
你这个问题的关键是使用了递归型的tree操作,tree的深度到了一定程度,怎么都会有call stack溢出的问题。即使你用一个pool来手动管理,要遍历或删除tree的一个分支时,只要还是递归型的tree操作,那还是老问题。解决方法是把tree操作写成非递归型的,请google non-recursive tree operation。
当然,对你的特定问题,如果不进行什么分支操作,能接受最后整颗树一起释放,那你把每次new出来的指针保存在一个list里最后统一delete就行了,即yangff的方法。 |
19
1423 2015-02-28 12:32:09 +08:00 via Android 1
。。。这不是析构的问题。。而是你那个 test 对象是在栈上的,他内部又有一个 map 而不是 map 的指针,你在循环中不断增大这个 map 的大小,他越来越大,就爆了,不过在 Mac 上想爆还真是得等好一会。
最后想说一个类的大小最好是常量,你这里完全可以用指针或引用 |
20
raincious OP |