虽然取名叫node多线程插件,但是目前还是在学习c++的情况。
今天谈一谈c++指针。
c++指针就像是c#中的引用变量,例如一个Person类的实例zs{Name="张三",Age=18,Gender='男'}。我们知道c#中的引用变量在栈内存中开辟了一块内存一个地址,这个地址是这个对象实例在堆内存上的地址,也就是说通过这个引用,系统会去堆内存寻找这块内存上的数据。
c++的指针就是这样的东西,指针本身保存在栈中,保存一个地址,这个地址指向一块堆内存。
目前我用到的c++非指针变量都是存在栈上的,即便是一个Person类的实例对象,比如上面的zs
Person zs= Person("张三",18,'男');
Person zs("张三",18,'男');
上面两种写法是一样的,创建一个Person类的实例,但是和c#不同的是,这些数据是保存在栈里面的,因为没有申请堆内存,所以我们自己只能使用栈内存。这有点像c#的结构(struct)。
如果要申请堆内存,就要使用new去申请
Person* zs = new Person("张三",18,'男');
通过new出来的东西就是去申请堆内存,返回的是该类型的指针。
关于class和struct的区别
c++中感觉没有什么区别,c#中结构是全保存在栈中的数据结构,而类是保存在堆中的数据结构,但在c++中都可以不适用new,从而保存数据在栈中,也都可以使用new,让数据保存在堆中得到这个实例的指针。
当然还是有一些细节差别,这个网上有很多文章,我不再赘述。
关于垃圾回收
c++中没有自动回收这么一说,所以请求的内存在使用完毕后应该立即回收。
这里提一个词:内存泄漏,就是指用完的内存没有进行回收,比如
while(true){Sleep(5000);//创建一个对象},
这句代码可能在c#中因为自动回收,隔一段时间创建的对象就会被回收没有什么问题。
在c#中这段代码"可能"不会报错,仅仅是可能,我没有试过。
但在c++中一定会异常,因为请求的内存没有释放。
这里首先要明确一点,需要释放的内存指的是堆内存。栈内存在其作用域末尾(即大括号结尾)就被释放了,但是堆中的内存,也就是new的内存必须被手动释放,使用delete关键字,删除指针所指向的对象,即释放该对象占用的内存
delete zs;
但要注意一点,被释放的内存仅仅是对象本身的内存,如果对象有指针成员,这个成员是不会被释放的。
zs->Child ---> Person* zhangsi//假设Person对象有一个属性Child,是一个Person类型的指针
这个指针指向的内存并不会因为zs的释放而被自动释放。
Person* zhangsan=new Person("张三",28,'男');
Person* zhangsi=new Person("张四",3,'男');
zhangsan->Child=zhangsi;
delete zhangsan;
cout<< zhangsi->Name <<endl; //打印张四,并没有异常
cout<< zhangsan->Name<<endl; //异常,该对象已经被删除
如果没有注意到这一点,还是会造成内存泄漏。所以如果要联级删除,就需要在析构函数里进行删除。但是可能存在别的地方需要用到这个指针,所以这里使用智能指针。说起来比较麻烦,到这里我自己也不是很懂了。
这对于我在做的这个插件是一个挑战。怎么说呢,首先我从来没有接触过这种自己释放内存的语言,所以还要花时间去摸索,其次假如子线程异常了怎么办。关于后者,我觉得应该没有问题,只要把错误控制在js的层面上就不会出什么错。但是c++的层面还需要去维护。
现在想到的问题如下:
1、v8函数执行问题,因为谷歌被墙了,国内也没有什么资料,v8的一些东西并不是很懂。
2、async/await被唤醒后的执行问题。这点可能要重写async/await关键字,主要是考虑到await后的执行区域最终被主线程接管了还是子线程在执行,这点要实验后才知道。
3、线程强制退出的资源回收问题。关于这一点,如果线程执行的js函数异常,只需要进行封装让他不会异常就行了,但是如果在c++层面上调用了terminate函数怎么释放资源。目前想法是直接不允许调用这个函数
4、线程间锁的问题。关于这点可以考虑使用c++11标准库的thread和mutex
今天内容如上,明天来研究v8的东西