Skia源码点滴
2015-08-19 11:59
162 查看
今天在看SkCanvas类的save()方法时看到两行code,有点不解,具体如下:
加粗的两行code中,第二行的new关键字用法有些不解,然后百度之,解释如下:
关键字new在堆上动态创建一个对象时,它实际上做了三件事:获得一块内存空间、调用构造函数、返回正确的指针。
当然,如果我们创建的是简单类型的变量,那么第二步会被省略。
假设有如下类A:
那么上述动态创建一个对象的过程大致相当于以下三句话(只是大致上):
new operator就是我们平时所使用的new,其行为就是前面所说的三个步骤,我们不能更改它。operator new是用来重载new操作符,示例如下:
new的第三种形态——placement new是用来实现定位构造的,因此可以实现new operator三步操作中的第二步,也就是在
取得了一块可以容纳指定类型对象的内存后,在这块内存上构造一个对象。
对头文件<new>或<new.h>的引用是必须的,这样才可以使用placement new。这里
operator的一个步骤而已。使用new operator地编译器会自动生成对placement new的调用的代码,因此也会相应的生成使用delete时调用析构函数的代码。如果是像上面那样在栈上使用了placement new,则必须手工调用析构函数,这也是显式调用析构函数的唯一情况: p->~A();
百度完毕。
SkCanvas类的save()方法在new一个新的栈帧时提前在堆中分配好了内存,然后在这个分配好的内存中构造了栈帧。
int SkCanvas::save() { this->willSave(kMatrixClip_SaveFlag); return this->internalSave(kMatrixClip_SaveFlag); }
int SkCanvas::internalSave(SaveFlags flags) { int saveCount = this->getSaveCount(); // record this before the actual save <strong> MCRec* newTop = (MCRec*)fMCStack.push_back(); new (newTop) MCRec(fMCRec, flags); // balanced in restore()</strong></strong> fMCRec = newTop; if (SkCanvas::kClip_SaveFlag & flags) { fClipStack.save(); } return saveCount; }
加粗的两行code中,第二行的new关键字用法有些不解,然后百度之,解释如下:
关键字new在堆上动态创建一个对象时,它实际上做了三件事:获得一块内存空间、调用构造函数、返回正确的指针。
当然,如果我们创建的是简单类型的变量,那么第二步会被省略。
假设有如下类A:
class A { int i; public: A(int _i) :i(_i*_i) {} void Say() { printf("i=%dn", i); } ; //调用new: A* pa = new A(3);
那么上述动态创建一个对象的过程大致相当于以下三句话(只是大致上):
A* pa = (A*)malloc(sizeof(A)); pa->A::A(3); return pa;C++中一提到new,至少可能代表以下三种含义:new operator、operator new、placement new.
new operator就是我们平时所使用的new,其行为就是前面所说的三个步骤,我们不能更改它。operator new是用来重载new操作符,示例如下:
class A { public: void* operator new(size_t size) { printf("operator new calledn"); return ::operator new(size); //这里通过::operator new调用了原有的全局的new } };
new的第三种形态——placement new是用来实现定位构造的,因此可以实现new operator三步操作中的第二步,也就是在
取得了一块可以容纳指定类型对象的内存后,在这块内存上构造一个对象。
#include <new.h> void main() { char s[sizeof(A)]; A* p = (A*)s; new(p) A(3); //p->A::A(3); p->Say(); }
对头文件<new>或<new.h>的引用是必须的,这样才可以使用placement new。这里
new(p) A(3);这种奇怪的写法便是placement new了,它实现了在指定内存地址上用指定类型的构造函数来构造一个对象的功能,后面A(3)就是对构造函数的显式调用。这里不难发现,这块指定的地址既可以是栈,又可以是堆,placement对此不加区分。但是,除非特别必要,不要直接使用placement new ,这毕竟不是用来构造对象的正式写法,只不过是new
operator的一个步骤而已。使用new operator地编译器会自动生成对placement new的调用的代码,因此也会相应的生成使用delete时调用析构函数的代码。如果是像上面那样在栈上使用了placement new,则必须手工调用析构函数,这也是显式调用析构函数的唯一情况: p->~A();
百度完毕。
<strong> MCRec* newTop = (MCRec*)fMCStack.push_back(); new (newTop) MCRec(fMCRec, flags); // balanced in restore()</strong>
SkCanvas类的save()方法在new一个新的栈帧时提前在堆中分配好了内存,然后在这个分配好的内存中构造了栈帧。
相关文章推荐
- 数据库中的多表查询问题
- 今天开始慢下脚步,开始ios技术知识的查漏补缺。
- 强大的wget
- JavaScript中解决多浏览器兼容性问题的方案
- MySQL中出现乱码问题的终极解决宝典
- b1
- Android中ScrollView中嵌套ViewPager导致ViewPager不显示的问题
- HDU2084
- Nginx动静分离经典案例配置
- CCDirector(2)
- CSS布局 ——从display,position, float属性谈起(转)
- hdoj1242(dfs 剪枝 解法)
- 编程这几天出现的很2的问题!!!
- Mac zend studio 12.0.2中国免费使用办法破解汉化
- button 添加图片防止被渲染
- [LeetCode]Word Search --
- 针对高版本timpicker/datepicker中ontimeset执行两次的解决办法
- Postfit 不能群发邮件的问题
- EXT.JS初学配置
- JSP页面使用JSTL日期对比