Cocos2d-x 的内存管理(2)
#include <stdio.h>
class Test {
public:
Test() {
test_ = __LINE__;
printf("Test(): Run Code in %d\n", __LINE__);
}
~Test() {
test_ = __LINE__;
printf("~Test(): Run Code in %d\n", __LINE__);
}
void print() {
printf("%d\n", test_);
}
private:
int test_;
};
void test() {
Test *temp = new Test;
delete temp;
Test *temps = new Test[2];
delete []temps;
Test *error_delete_temps = new Test[2];
delete error_delete_temps;
}
int main(int, char **) {
test();
return 0;
}
上面的代码最后用delete删除了使用new[]分配的内存, 但是编译时即使开启-wall选项, 你也不会看到任何的警告, 运行时也不会报错, 你只会发现析构函数少运行了一次. 实际上就是发生了内存泄漏.
C/C++内存管理的实际使用
上面虚构的例子也就是看看语法, 真实的使用情景就要复杂了很多. 最重要的原则之一就是谁分配谁释放原则. 这个原则即使是用malloc, free也一样需要遵循.
在C语言上的表现形态大概如下:
只管用, 不管分配
典型的例子就是C语言的文件读取API:
size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
这里的ptr buffer并不由fread内部分配, 而是由外部传进来, fread只管使用这段buffer, 并且假设这段buffer的size 大于等于传进来的size. 通过这样的方式, fread本身逃避了malloc, free的责任, 也就不用关心内存该怎么管理的问题. 好处是fread的实现得到简化, 坏处是外部使用的负担增加了~~~
类似的API还有sprintf, fgets等, 而strcat这种API也算是这种类型的变化.
这种类型的API的一个最大问题在于很多时候不好确定buffer到底该多大, 于是在一些时候, 还有一个复杂的用法, 那就是在第一次传特定参数调用函数时, 函数仅传出需要buffer的大小, 分配了buffer后, 第二次调用才真正实现函数的功能.
这种API虽然外部的使用麻烦, 但是在绝大部分时候, 已经是C语言的最佳API设计方法.
管分配, 也管删除
只管用, 不管分配的API设计方式在仅仅需要一个buffer, 或者简单的结构缓存的时候基本已经够用, 但也不是万能的, 在想要隐藏内部实现时, 往往就没法使用这样的API设计, 比如Windows API中一系列与核心对象创建相关的方法, 如CreateThread, CreateProcess等函数返回的都是一个核心对象的handle, 然后必须要使用CloseHandle来释放, handle具体的对应什么结构, 分配了多少内存, 此时并不由我们关心, 我们只需要保证一个CreateXXX, 就一定要CloseHandle即可.
这种API的设计方式, 还常见于我们熟知的工厂模式, 工厂模式提供Create和Delete的接口, 就要比只提供Create接口, 让外部自己去Delete要好的多, 此时外部不用关心对象的删除方式, 将来需要在创建对象时进行更多操作(比如对对象进行引用计数管理), 外部代码也不需要更改. 我在网上随便一搜, 发现绝大部分关于工厂模式的代码中都没有考虑这个问题, 需要特别注意.
这里看一个我们常见的开源游戏引擎Ogre中的例子: (Ogre1.8.1 OgreFileSystem.h)
/** Specialisation of ArchiveFactory for FileSystem files. */
//class _OgrePrivate FileSystemArchiveFactory : public ArchiveFactory
相关新闻>>
- 发表评论
-
- 最新评论 更多>>