关于A函数申请内存,B函数释放大家有什么好的解决方法
大家编程时,难免会遇到这种问题,但遵循的原则一般都是谁申请 谁释放。
假设函数B需要从文件中读到一写数据,为了模块化的目的,我可能把操作文件数据的函数都独立出来,使函数B看不到具体的文件结构细节。于是函数B为了得到数据,必须访问上述操纵数据的Api(假设为函数A)。
因为B不知道数据的具体大小,所以所需要malloc的空间也不知道多大,因此把申请空间的工作交给A来做了,最后由B来释放A申请的内存。这也就是上面提出的A申请,B释放的缘由,但好像大家不喜欢这样的编程方式,一般都遵循谁申请 谁释放的原则。
请问大家对此有何解决办法?
我现在想到一种解决方法是:在B中传递一个二维指针,即地址的地址,这样的话A把申请的地址放到B中,但仍避免不了这个问题。
问题点数:50、回复次数:43Top
1 楼jixingzhong(瞌睡虫·星辰)回复于 2006-05-28 11:28:05 得分 2
一般都是 谁申请谁释放,
但是这个也不是绝对的 ......
在 B 中释放也完全可以,
只不过需要注意很多问题,
存在一些潜在的状况而已 ....Top
2 楼CodeMagic(ErrorDetector)回复于 2006-05-28 11:39:15 得分 0
但是如果由B申请,B释放的话,因为B不知道提前malloc空间的大小,需要A那边另外做一个接口,获得申请的大小,然后B再根据这个大小来申请需要的空间。
至于这个接口是不是需要单独做成一个函数,还是由函数A来承担,那只是实现上的事情了。
是不是只有这么一种解决方案了?Top
3 楼samoonm()回复于 2006-05-28 12:38:14 得分 1
在数据里面记录自身的大小行不行?Top
4 楼CodeMagic(ErrorDetector)回复于 2006-05-28 14:37:28 得分 0
那也可以,那就是让B提前知道这个大小了Top
5 楼vincentcsdn(DemonPumpkin)回复于 2006-05-28 15:49:06 得分 1
可以使用智能指针。
例如CString ,String auto_ptr 之类的
也可以根据需要自己订制.Top
6 楼CodeMagic(ErrorDetector)回复于 2006-05-28 16:05:06 得分 0
老大,c语言支持么?Top
7 楼Kenmark(fenix)回复于 2006-05-28 17:44:30 得分 1
不太好地习惯,容易造成内存归属不明确,应该是谁非配谁管理,OO就是要实现这种功能,类自己地事情自己管,大的工程如果是用A分配B释放地方法会让人头疼地!Top
8 楼CodeMagic(ErrorDetector)回复于 2006-05-28 19:23:58 得分 0
那有好的解决方法么,除了我给的这种?
但是如果由B申请,B释放的话,因为B不知道提前malloc空间的大小,需要A那边另外做一个接口,获得申请的大小,然后B再根据这个大小来申请需要的空间。
至于这个接口是不是需要单独做成一个函数,还是由函数A来承担,那只是实现上的事情了。Top
9 楼crazy_lazy_pig(疯狂懒猪)回复于 2006-05-28 20:11:10 得分 2
为什么一定要由A来申请呢? 我认为这即会出现麻烦, 也不易读, 更不易维护, 至于运行质量不是很好评价了.
我认为可以让A仅返回文件大小(即malloc需要的大小), 然后在B中调用A, 进而申请空间.
还有, 你的问题我在逻辑上有点想不通: B用来获取文件数据, A用来处理数据, 但是B不知道申请多大的空间, 为了安全的读数据必须由A的处理数据功能来申请空间, 可是A自己得不到数据, 必须由B来获取数据. 这样B为了读数据需要等待A的结果, A给出结果需要B的数据, 这不是死锁了吗?Top
10 楼CodeMagic(ErrorDetector)回复于 2006-05-28 21:32:42 得分 0
是这样的,我现在做嵌入式开发,上层界面那一部分是不应该涉及到底层数据的处理逻辑的(例如直接打开文件,移动文件指针来读取数据。这样做会导致代码的维护性差,一旦底层文件的结构发生变化,就得改上层的处理逻辑),所以我把数据的处理单独做一些函数来供界面使用。这里的函数B处于界面那一层,函数A处于数据处理那一层了。Top
11 楼jiangsheng(蒋晟.Net[MVP])回复于 2006-05-28 22:01:35 得分 2
Implement IUnknown
marshal calls between threadsTop
12 楼CodeMagic(ErrorDetector)回复于 2006-05-28 22:17:53 得分 0
One point i must mention, the language i use is C, not C++
And dont interven the concept of threadTop
13 楼cattlenzq(吃狼的豆腐(不要给分了,散起来真麻烦!))回复于 2006-05-28 22:32:03 得分 1
实在不行就在析构函数解决吧Top
14 楼crazy_lazy_pig(疯狂懒猪)回复于 2006-05-28 23:15:38 得分 2
真搞不懂你的设计思路是什么, 我认为还是设计理念上有问题, 逻辑上还是讲不通.
界面无非就是人机对话界面, 它无疑是要处理输入和输出, 而底层功能模块是作数据处理. 然而, 输入与输出也是与数据结构紧密相连的, 这就牵扯到界面模块和底层模块如何划分的问题了. 我没用C写过类似的程序, 但是C++的GUI编程思想是这样的: 界面(GUI)是数据无关的, 即窗口,菜单,对话框等(有没有数据, 有什么样的数据, 我的窗口,菜单等东西都可以那么样画), 而数据相关的内容(包括文件存贮)都放到了底层(也就是说没有GUI, 我一样可以存取文件), 界面模块是通过调用底层模块来实现功能的.
所以我认为, 你的文件读取函数肯定要放到底层去的, 而界面仅仅是调用这个函数而已, 这样, 无论你怎么改数据处理函数, 界面都可以不变的.Top
15 楼CodeMagic(ErrorDetector)回复于 2006-05-28 23:53:32 得分 0
是呀,现在就是这样设计的,界面不知道底层数据的组织,只需要调用相应的函数而已,关键在于内存的分配上。Top
16 楼happytang(一只叫苏格拉底的猪)回复于 2006-05-29 00:05:09 得分 1
定义一个全局的结构,比如消息队列,通过传递消息来申请和释放
这在嵌入式系统中很容易实现Top
17 楼wxfy1977(我心飞扬)回复于 2006-05-29 09:35:25 得分 1
在A中返回分配的大小,传回分配的地址Top
18 楼magicianxcs()回复于 2006-05-29 10:17:19 得分 1
可以参考windows API 函数的设计。Top
19 楼BluntBlade(信仰迷离·重构之道,在于Redo/Undo之间)回复于 2006-05-29 10:25:19 得分 2
对待处女,谁污染,谁治理;
对待内存,谁分配,谁释放。
如果感觉不对劲,请重新设计你的软件。Top
20 楼Muf(沐枫)回复于 2006-05-29 11:04:45 得分 2
关于文件处理,现有的许多API都已经是很成熟了。
比如A是用于读取文件数据的,B是用于处理数据的。
这里:
1. A是如何读取数据呢?全部读还是部份读,将来如果想要读任意大小怎么办?
2. B是如何处理数据呢?全部处理还是部份处理,将来如果只想处理其中的部份数据怎么办?
所以,关键是A能不能提供一个灵活的接口。
可以参考fread函数:由B提供缓冲区,并告诉A,缓冲区的大小,由A来读取相应大小的数据。
这样,问题不就结了。Top
21 楼CodeMagic(ErrorDetector)回复于 2006-05-29 12:17:12 得分 0
是这样的,如果让A来申请内存,那么A可以对malloc的结果进行统一判断,如果让B来做这件事情,那么可能有若干个类似于B的函数,都需要调用A,那么对malloc结果的判断,有多少调用就得的重复多少次判断。Top
22 楼Muf(沐枫)回复于 2006-05-29 13:39:26 得分 2
是的,这才是应该 做的。
因为,对malloc的结果判断,有时候是必须的,有时候不是必须的。而且,有时候用malloc分配比较好,有时候用数组比较好,有时候用系统分配(如GlobalAlloc)。让B去做这些事,可以保证A是最好的。Top
23 楼cutenoob(cute )回复于 2006-05-29 15:56:58 得分 2
我现在想到一种解决方法是:在B中传递一个二维指针,即地址的地址,这样的话A把申请的地址放到B中,但仍避免不了这个问题。
-------------------
请问lz 你这种方法的缺陷又在哪里?我也想到这种方法了....
Top
24 楼CodeMagic(ErrorDetector)回复于 2006-05-29 16:28:47 得分 0
容易导致内存泄露,因为你需要关心从别的函数得来的指针是否需要自己释放Top
25 楼wgjmail(笑面佛)回复于 2006-05-29 18:11:28 得分 1
传个文件长度的变量不就行了.Top
26 楼FreeFice(庄鱼)回复于 2006-05-29 18:25:31 得分 2
符合下述规则:
class A;
A *make(A &a)//()
{
return new A(a);//new A();
}
void Free(A* &a)
{
if(a){
delete a;
a=0;}
}
也可以使用下述函数获取指针:
int NewOne(A **a){
if(*a)
return ERROR;
try{
*a = new A();}
catch(...){
return FAIL;}
return OK;
}Top
27 楼Wolf0403(废人:独活十年~心如刀割)回复于 2006-05-29 19:53:14 得分 1
我觉得 A 分配 B 释放未必就是洪水猛兽。。只要能通过某种方法使 A 和 B 对需要释放的资源达成共识就可以了……Top
28 楼Wolf0403(废人:独活十年~心如刀割)回复于 2006-05-29 19:56:41 得分 1
另外,底层和 GUI 之间共享数据,我不明白为什么不能由底层来释放资源。。Top
29 楼crazy_lazy_pig(疯狂懒猪)回复于 2006-05-29 22:53:55 得分 2
lz 的意思我终于看明白了, 这里面的问题确实非常的多, 这就是面向对象思想出现的原因, 也最终相对于C语言出现了C++. 你的问题在C++里似乎得到了比较好的解决, 下面是我作的程序的大体思路:
我的程序主要是三个类相互配合协同完成各功能command类实现内存的申请与施放, document实现数据的各种处理, view负责把document的内容显示的屏幕上, 并调用command的公有函数实现对document数据的增减. 这里view属于界面部分, 另外两个类属于底层. 这里面view不带有数据, 仅仅是通过调用document里的函数来显示数据(document的变化毫不影响view), document的有效数据都是指针, 指向command申请出来的对象. command带有有效的成员变量, 在构造函数里通过new来申请空间, 析构函数里施放空间, 并由view的桥梁作用来充实(减少)document的数据. 下面的关键问题就是保证command对象的生存时间比document内的数据生存时间要长, 这很容易实现, 只要在你的程序里让command的地位比document更底层就可以了. 其实现在的GUI库都已经充分考虑到了这些问题, 它会自动给你处理好的.
Top
30 楼crazy_lazy_pig(疯狂懒猪)回复于 2006-05-29 23:03:00 得分 1
再稍微解释一下command比document更底层的意义:
在我的程序里, command完全负责document的数据的增减, 在command内部有标志变量标明当前状态是给document增了数据还是减了数据(其实真正的实现还要更复杂,甚至于标明了增减的数据类型以及状态), 只有当状态是减的时候(这时document已不含有该command的数据指针了), command对象才有消亡的可能(这当然是有某种机制可以控制的).Top
31 楼crazy_lazy_pig(疯狂懒猪)回复于 2006-05-29 23:04:54 得分 1
呵呵, 胡说一通, 不知道这种思想能不能被你转化到C程序中去.Top
32 楼HeShe(呵呵)回复于 2006-05-30 10:52:26 得分 2
我觉得在C中这其实也是一种比较普遍的情况。一般将数据本应该是一个实体,对其封装,统一管理。
typedef _HANDLE
{
char*pData;
int iDataLen;
}*DATAHANDLE;
DATAHANDLE A_CreateData()
{
DATAHANDLE p=malloc(struct _HANDLE);
}
ClosHandle(DATAHANDLE handle)
{
free(handle->pData);
free(handle);
}
B(DATAHANDLE handle)
{
CloseHandle(handle);
}
个人偏好在B外面CloseHandle(handle):
mail()
{
handle=A_CreateData();
B(handle);
CloseHandle(handle);
}Top
33 楼redsocks()回复于 2006-05-30 11:43:04 得分 1
HeShe(呵呵) 的做法比较好!支持!Top
34 楼iambic()回复于 2006-05-30 11:58:11 得分 1
比较简单的方法就是细分函数职能,统一函数名。把内存的申请释放统一使用newType(),deleteType(T* p),可以在其中增加内存管理(比如记录申请并未归还的内存)。这是一种风格,不是保障机制。但这种风格往往能提醒你少犯错误。Top
35 楼studiovc()回复于 2006-05-30 18:06:48 得分 2
b();
getBsize();
a()
{
long lbsize;
lbsize=getBsize();
malloc();
....
free();
}
Top
36 楼tjuzhangrui()回复于 2006-07-05 15:28:49 得分 2
关于文件处理,现有的许多API都已经是很成熟了。
比如A是用于读取文件数据的,B是用于处理数据的。
这里:
1. A是如何读取数据呢?全部读还是部份读,将来如果想要读任意大小怎么办?
2. B是如何处理数据呢?全部处理还是部份处理,将来如果只想处理其中的部份数据怎么办?
所以,关键是A能不能提供一个灵活的接口。
可以参考fread函数:由B提供缓冲区,并告诉A,缓冲区的大小,由A来读取相应大小的数据。
这样,问题不就结了。
--------------------------------------------------
恕我直言,我觉得为了遵循“谁申请谁释放”的原则这么写函数是一个比较SB的做法,因为有时候你不知道要开多大的内存。但是如果遵循这个原则我又想不出更好的办法,也想不出这么做的好处在哪,所以只好A申请,B释放。谁能为我解惑啊。Top
37 楼tjuzhangrui()回复于 2006-07-05 15:34:52 得分 2
crazy_lazy_pig(疯狂懒猪) ( ) 信誉:100 2006-5-29 22:53:56 得分: 0
lz 的意思我终于看明白了, 这里面的问题确实非常的多, 这就是面向对象思想出现的原因, 也最终相对于C语言出现了C++. 你的问题在C++里似乎得到了比较好的解决, 下面是我作的程序的大体思路:
我的程序主要是三个类相互配合协同完成各功能command类实现内存的申请与施放, document实现数据的各种处理, view负责把document的内容显示的屏幕上, 并调用command的公有函数实现对document数据的增减. 这里view属于界面部分, 另外两个类属于底层. 这里面view不带有数据, 仅仅是通过调用document里的函数来显示数据(document的变化毫不影响view), document的有效数据都是指针, 指向command申请出来的对象. command带有有效的成员变量, 在构造函数里通过new来申请空间, 析构函数里施放空间, 并由view的桥梁作用来充实(减少)document的数据. 下面的关键问题就是保证command对象的生存时间比document内的数据生存时间要长, 这很容易实现, 只要在你的程序里让command的地位比document更底层就可以了. 其实现在的GUI库都已经充分考虑到了这些问题, 它会自动给你处理好的.
---------------------------------------------------------------------------
有一个问题是,“command带有有效的成员变量, 在构造函数里通过new来申请空间”,构造函数怎么知道申请多大的空间?谢谢!Top
38 楼tailzhou(尾巴)回复于 2006-07-05 16:05:52 得分 1
好多api函数好象都是第一次调用获取需要的空间的大小;
分配好空间后;
使用分配的地址作为参数再次调用api函数.
Top
39 楼crazy_lazy_pig(疯狂懒猪)回复于 2006-07-05 16:12:03 得分 2
恩,这是个问题。
我的程序只是一个对象一个对象的申请空间,应该是view(或者是document)知道需要多少对象,需要几个就生成几个command,不过这样讲似乎command就等价于数据了。但是我的command对象都是在栈空间里的,它是由系统决定存亡的,不用我操心,我所做的是把需要我操心的数据封装进了command类内。但是这似乎又有了问题,既系统把command对象析构掉时,是否还会有其他对象需要用到析构掉的数据?唉,实在是晕啊,我也不知道答案了。但是我从来还没出过问题,想必GUI库的document/view架构已经充分为我们考虑到了这些问题,我没好好研究过,研究研究这个机制应该会找到答案吧。Top
40 楼cc203203(为了过日子!)回复于 2006-07-26 09:54:30 得分 1
路过~~Top
41 楼SammyLan((基础决定你能走多远)--英语菜才是真的菜)回复于 2006-07-26 10:08:11 得分 2
A函数申请内存,B函数释放内存.....
为什么这都有那么多异议
在DLL编程中这是很常用的方法:在DLL中分配的内存必须由在DLL里面释放,所以提供一个分配内存的函数,必须要同时提供一个释放内存的函数.
看一下那么多系统函数就知道了,像GlobalAlloc(),HGLOBAL GlobalFree(),etc............
在C中不直接支持面向对象
A函数申请内存,B函数释放内存正是面向对象思想的体现Top
42 楼SammyLan((基础决定你能走多远)--英语菜才是真的菜)回复于 2006-07-26 10:52:34 得分 2
...............这里的函数B处于界面那一层,函数A处于数据处理那一层了。
为什么函数B要放在界面一层,分配和释放的话函数要放在同一层,老大(=_=)
要是在模块化编程中,你将A封装在一个DLL,B却在另一模块,麻烦就大了Top
43 楼CodeMagic(ErrorDetector)回复于 2006-11-30 21:52:13 得分 0
不好意思,分不多,就这样吧。Top




