|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
你可以配置MySQL运行在微小的嵌入式应用程序中,处理的数据可能不足1Mb??而你也可以用它来处理数Tb的数据。MySQL获得这种可扩展性的路径之一是通过一个人们所熟知的存储过程,这是一个运行在程序之外的微型、预编译程序。c++|object|工具
C++永世工具存储(PersistentObjectStorageforC++)
简介形貌工具范例从存储器平分配和开释工具永世工具协定存储器机关函数翻开存储器POST++的安装POST++类库和POST++一同利用STL类交换尺度分派子怎样利用POST++S调试POST++使用的细节关于POST++更多的一些信息简介
POST++供应了对使用工具的复杂无效的存储.POST++基于内存文件镜像机制和页面镜像处置。POST++打消了对永世工具会见的开支.别的POST++撑持多存储,虚函数,数据更新原子操纵,高效的内存分派和为指定开释内存体例下可选的渣滓搜集器.POST++一样能够很好的事情在多承继和包括指针的工具上。
形貌工具范例
POST++存储办理必要一些信息以使永世工具范例撑持渣滓搜集器,装载时援用重定位和初始化虚表内函数指针。但不幸的是C++言语没有供应运转时从类中也许这些信息的机制。为了不利用一些特别的工具(预处置器)或“脏利用”路子(从调试信息中猎取类信息),这些信息必需由程序员来指明。这些称为类注册器的器材能够复杂的经由过程POST++供应的一些宏来完成。
POST++在从存储重视载进工具时挪用缺省机关函数来初始化工具。为了使工具句柄可以存储,程序员必需在类界说中包括宏CLASSINFO(NAME,FIELD_LIST).NAME指明工具的名字。FIELD_LIST形貌类的的援用字段。在头文件classinfo.h界说了三个宏用于形貌字段:
REF(x)形貌一个字段.REFS(x)形貌一个一维流动数组字段。.(比方:定长数组).VREFS(x)形貌可变一维数组字段。可变数组只能是类的最初一个成员。当你界说类的时分,你能够指定一个仅包括一个元素的数组。详细工具实例中的元素个数能够在天生时指定。
这些宏列表必需用空格分隔:REF(a)REF(b)REFS(c).宏CLASSINFO界说了缺省机关函数(没有参数的机关函数)和类形貌符.类形貌符是类的一个静态成员名为self_class.如许类foo的形貌符能够经由过程foo::self_class会见.基类和成员的缺省机关函数会被编译器主动挪用,你不用忧虑必要明白挪用他们。可是关于序列化的类中的布局成员不要健忘在布局界说中利用CLASSINFO宏。然后经由过程存储器办理注册该类使其可被会见。这个历程由宏REGISTER(NAME)完成。类名将和工具一同放在存储器中。在翻开存储器的时分类在存储和使用程序之间被镜像。存储器中的类名和程序中的类名举行对照。假如有类没有被程序界说或使用程序和存储器中的类有分歧的巨细,程序断言将失利。
上面的例子论述了这些划定规矩:
structbranch{object*obj;intkey;CLASSINFO(branch,REF(obj));};classfoo:publicobject{protected:foo*next;foo*prev;object*arr[10];branchbranches[8];intx;inty;object*childs[1];public:CLASSINFO(foo,REF(next)REF(prev)REFS(arr)VREFS(linked));foo(intx,inty);};REGISTER(1,foo);main(){storagemy_storage("foo.odb");if(my_storage.open()){my_root_class*root=(my_root_class*)my_storage.get_root_object();if(root==NULL){root=new_in(my_storage,my_root)("someparametersforroot");}...intn_childs=...;size_tvarying_size=(n_childs-1)*sizeof(object*);//Weshouldsubtract1fromn_childs,becauseoneelementisalready//presentinfixedpartofclass.foo*fp=new(foo:self_class,my_storage,varying_size)foo(x,y);...my_storage.close();}}
从存储器平分配和开释工具
POST++为了办理存储内存供应了出格的内存分派子.这个分派子利用两种分歧的办法:针对分派小工具和年夜工具。一切的存储内存被分别为页面(页面的巨细和操纵体系的页面巨细有关,今朝版本的POST++中接纳了512字节).小工具是如许一些工具,他们的巨细小于或即是256字节(页面巨细/2).这些工具被分派成流动巨细的块链接起来。每个链包括不异巨细的块。分派工具的巨细以8个字节为单元。为每一个工具分派的包括这些块巨细为256的的链的数目最好不要年夜于14(分歧的平衡页面数).在每一个工具之前POST++分派一个工具头,包括有工具标识和工具巨细。思索到头部恰好8个字节,而且在C++中工具的巨细总年夜于0,巨细为8的块链能够舍弃。分派和开释小工具一般情形下长短常快的:只必要从L1行列中举行一次拔出/删除操纵.假如链为空而且我们试图分派新的工具,新页被分派用来存储像今朝巨细的工具(页被分别成块增加到链表中)。年夜工具(年夜于256字节)所必要的空间从余暇页行列平分配。年夜工具的巨细和页界限对齐。POST++利用第一次喂给随机定位算法保护余暇页行列(一切页的余暇段依照地点分列并用一个出格的指针跟从行列确当前地位)。存储办理的完成见文件storage.cxx
利用显式仍是隐含的内存开释取决于程序员。显式内存开释要快(出格是对小工具而言)可是隐含内存开释(渣滓搜集)加倍牢靠。在POST++中利用标记和扫除渣滓搜集机制。在存储中存在一个出格的工具:根工具。渣滓搜集器起首标记一切的工具可被根工具会见(也就是能够从根工具抵达,和经由过程援用遍历)。如许在第一次GC阶段一切未被标记的工具被开释。渣滓搜集器能够在工具从文件载进的时分天生(假如你传送do_garbage_collection属性给storage::open()办法)。也能够在程序运转时代挪用storage::do_mark_and_sweep()办法挪用渣滓搜集器。可是请务必断定没有被程序变量指向的工具不成从根工具会见(这些工具将被GC开释)。
基于多承继C++类在工具中能够有非零偏移而且工具内也大概有援用。这是我们为何要利用出格的手艺会见工具头的缘故原由。POST++保护页分派位图,个中每个位对应存储器中的页。假如一些年夜工具分派在几个页中,一切这些工具占用的页所对应的位除第一个外都被置为1。一切其他页在位图中有对应清空位。要找到工具肇端地点,我们起首按页巨细分列指针值。然后POST++从位图中查找工具肇端页(该页在位图中有零位)。然后从页入手下手处包括的工具头中掏出工具巨细的信息。假如巨细年夜于页巨细的一半那我们已找到了工具形貌:它在该页的入手下手处。反之我们盘算页中所利用的流动块的巨细而且把页中指针偏移按块巨细盘算出来。这类头部定位计划被渣滓搜集器利用,类object界说了operatordelete,和被从工具头部剖析出工具巨细和类信息的办法利用。
在POST++中供应了出格重载的new办法用于存储中的工具分派。这个办法必要创立工具的类形貌,创立工具的存储器,和可选的工具实例可变部分的巨细作为分外的参数。宏new_in(STORAGE,CLASS)供应永世工具创立“语法糖”。永世工具能够被重界说的operatordelete删除。
永世工具协定
在POST++中一切的永世工具的类必需承继自object.h中界说的类object。这个类不含任何变量并供应了分派/开释工具及运转时失掉类信息和巨细的办法。类object能够是多承继中一个基类(基类的序次无所谓)。每个永世类必需有一个供POST++体系利用的机关函数(见Describingobjectclass一节)。这意味着你不克不及利用没有参数的机关函数来初始化。假如你的类机关函数乃至没有成心义的参数,你必需加一个假造的以和宏CLASSINFO创立的机关函数区分开来。
为了会见永世存储器中的工具程序员必要某种根工具,经由过程它可使用一般的C指针会见到每个其他工具。POST++存储器供应了两个办法用于指定和失掉根工具的援用:
voidset_root_object(object*obj);object*get_root_object();
当你创立新存储时get_root_object()前往NULL。你必要经由过程set_root_object()办法创立根工具而且在个中保留援用。下一次你翻开存储时,根工具能够经由过程get_root_object()失掉。
提醒:在实践使用中类一般在程序开辟和保护过程当中被改动。不幸的是POST++思索到的复杂没有供应主动工具转换的工具(拜见GOODS中的怠惰工具更新计划示例),以是为了不增加新的字段到工具中,我只能倡议你在工具中保存部分空间供未来利用。这对根工具来讲意义特别严重,由于它是新到场工具的优选者。你也必要制止转换根工具的援用。假如没有其他工具含有指向根工具的援用,那末根工具能够被复杂的改动(经由过程set_root_object办法)到新类的实例。POST++存储供应设置和获得村出书标识的办法。这个标识能够用于使用依据存储器和使用的版原本更新存储器中工具。
存储器机关函数
你能够在使用中同时利用几个存储器。存储器机关函数有一个必须的参数-存储文件路径。假如这个文件没有扩大名,那末POST为文件名增加一个后缀“.odb”。这个文件名也被POST++用于构成几个帮助文件的名字:
文件形貌利用机会后缀包括新存储器映像的一时文件用于非事件处置形式下保留存储器新映像".tmp"事件纪录文件用于事件形式下保留镜像页面".log"保留存储器文件备份仅用于Windows-95下重定名一时文件".sav"
存储器机关函数的另两个参数具出缺省值。第一个参数max_file_size指出存储器文件扩大限定。假如存储器文件年夜于storage::max_file_size那末它不会被切除可是也不成能更进一步的扩大。假如max_file_size年夜于文件巨细,举动依附于翻开存储器的形式。在事件形式下,文件在读写回护下被镜像到内存中。Windows-NT/95扩大文件巨细到max_file_size。文件巨细被storage::close()办法延长到存储器中最初一个工具的界限。在Windows中为了以读写形式翻开存储器必要在磁盘上最少有storage::max_file_size的余暇字节数即便你禁绝备向个中到场新工具。
存储器机关函数的最初一个参数是max_locked_objects,这个参数仅在事件形式下用于供应镜像页面的写事件纪录文件的缓冲区。为了供应数据分歧性POST++必需包管修正页在革新到磁盘前镜像页被保留在事件纪录文件中。POST++利用两个路子中的一个:同步纪录写(max_locked_objects==0)和在内存中页面锁定的缓冲写。经由过程内存中锁定页面,我们能够包管它在事件纪录缓冲钱不被互换到磁盘上。镜像页面在异步体例下被写到事件纪录文件中(包含启用操纵体系缓冲)。当锁定页面数凌驾max_locked_pages,纪录文件缓冲被革新到磁盘上而且一切锁定页面被解锁。这个办法能够明显的进步事件处置才能(在NT下进步了5倍)。可是不幸的是分歧的操纵体系利用分歧的办法在内存中锁定页面。
Windows95基本不撑持。在WindowsNT每一个历程能够锁定它的页面,可是锁定页面的总数不成以凌驾历程运转设置限定。在缺省情形下历程能够锁定凌驾30个的页面。假如你指定max_locked_pages参数年夜于30,那末POST++将试图扩大历程设置合适你的需求。可是从我的履历来看30个和60个锁定页面之间功能的差异长短常小的。在Unix下只要超等用户能够在内存中锁定页面。这是之以是文件机关函数反省历程是不是具有充足的权限利用锁定操纵。因而假如你指定max_locked_pages参数年夜于0,那末在存储类创立时将决意利用同步仍是异步写事件纪录文件。假如你但愿利用内存锁定机制带来的优点(2-5倍,依据事件范例),你必要改动你的使用的一切者为root而且赐与set-user-ID权限:chmod+sapplication.
翻开存储器
POST++利用内存内存映照机制会见文件中的数据。在POST++经由过程两个分歧的办法供应数据分歧性。起首并且加倍先辈的是基于事件机制利用的镜像页面在堕落厥后供应存储恢复和事件回滚。在写镜像页眼前创立运算被利用。这个运算以以下体例实行:一切文件映照页面被设置为只读回护。任何对这些页面的写会见将引发会见违背非常。这个非常被一个出格的句柄捕捉,它改动页面回护为可读写并放这个页面的拷贝在事件纪录文件中(纪录文件名为原文件名和后追“.log”的组合)。一切接上去这个页面的写操纵将不再引发页面毛病。存储器办法commit()革新一切的改动页面到磁盘上并截断纪录文件。storage::commit()办法被storage::close()隐含挪用。假如毛病在storage::commit()操纵前产生,一切的改动将经由过程拷贝事件纪录中改动的页面到存储数据文件被回复。一样一切的改动能够经由过程显式挪用storage::rollback()办法来回复。经由过程指定storage::open()办法的storage::use_transaction_log属性来选择文件会见事件所基于的形式.
别的一个供应数据分歧性的手腕基于写拷贝机制。在这类情形下源文件没有遭到影响。任何试图对文件镜像页面的改动,招致发生一个该页面的拷贝,它从体系互换区种分派并具有读写允许。文件直到显式挪用storage::flush()办法时才更新。这个办法写数据光临时文件(带后缀“.tmp”)然后重定名为本来的。因而这个操纵构成文件的一个原子更新(固然假定在操纵体系能包管rename()操纵的原子数)。
注重:假如你没有利用事件处置,storage::close()办法不会刷数据到文件中。以是假如你在此前挪用storage::flush()办法一切的自前次flush以后的改动将会丧失。
Windows95细节:在Windows95中重定名到已有的文件是不可的,以是源文件起首被保留为带后缀“.sav”的文件名。然后后缀为“.tmp”的一时文件被重定名为本来的名字和最初的旧的拷贝被删除。以是假如毛病产生在flush()操纵中而且以后你找不到存储文件,请不要惊惶,只需找到今后缀“.sav”停止的文件而且重定名为本来的就能够了。
提醒:假如你企图在程序实行时代保留数据我激烈倡议你利用事件处置。也能够接纳写拷贝的路子可是如许必要多很多的损耗。一样假如存储十分年夜事件处置也一般更好,由于天生一时的文件拷贝必要良多的磁盘空面和工夫。
这里有几个属性供存储器open()办法利用:
support_virtual_functions假如存储器中的工具带有虚函数则必需设置这个属性。假如没有设置这个属性,POST++假定一切的永世工具在存储中只包括有援用(对存储器中其他工具的)。以是只要在数据文件映像的基地点产生改动时才必要调剂援用(这个地点被寄存在数据文件的第一个字中而且POST++一般试图映像文件到不异的地点下去制止不用要的援用调剂)。可是假如工具类包括虚函数,指向虚表的指针被放在工具内。假如你从头编译你的使用,这个标的地点大概改动。POST++库对照实行工具的工夫戳和这个使用发生的数据库的工夫戳举行对照。假如这个工夫戳不等的话,则会校订虚表的指针。为了失掉使用工夫戳POST++必需能够定位实行文件工具。不幸的是没有找到实行文件名的烦琐的办法。在Unix下POST++看命令行注释器设置的情况变量“_”的值。但假如历程不是从命令行实行的(好比经由过程system())大概事情目次被chdir()改动这个办法将不起感化。最复杂的办法是利用文件comptime.cxx,它必需在每次重编译你的使用时被编译并和存储库一同被链接。在Windows中没有这个成绩,实行映像的称号能够经由过程Win32API失掉。在存储器翻开时POST++对照这个工夫戳和数据文件的工夫辍,假如他们不等而且指定了support_virtual_functions属性那末校订一切工具(经由过程挪用缺省机关函数)。read_only经由过程设置这个属性程序员申明他只必要数据文件读权限。POST++将创立数据文件的只读视图而且任何改动存储器中的工具大概分派新工具的实验将会招致回护背例错。这里有一个破例:假如不克不及够映像数据文件到不异的地点大概使用程序产生改动时而且指定了support_virtual_functions,那末对此地区的回护被一时改动为写拷贝而且装载的工具被转换。use_transaction_log设置这个属性强迫对一切数据文件更新利用事件。影子页面被用来实行事件。事件在第一次修正存储后被翻开。经由过程storage::commit()大概storage::rollback()操纵显式的封闭。办法storage::commit()保留一切的改动页面到磁盘上而且截断事件纪录,办法storage::rollback()疏忽此次事件中的一切改动。no_file_mapping缺省情形下POST++将映像数据文件到历程假造内存中。这类情形下翻开数据库的工夫将年夜年夜削减,由于文件页面将在必要时调进。可是假如数据库巨细不是出格年夜大概数据库中一切数据必要当即会见,那末把文件读进内存优于利用假造内存映像由于这类情形下没有分外的页面溢堕落误。标记no_file_mapping制止POST++映像文件并依据分派的内存段读文件。fault_tolerant这个标记被使用程序用于在体系或使用堕落情形下想回护数据库的分歧性。假如利用了事件use_transaction_log这个标记不用指定,由于分歧性能够由事件机制来供应。假如没有指定use_transaction_log标记而且设置了fault_tolerant标记,POST++将不改动源文件而坚持它的分歧性。这依托读文件到内存中(假如没有设置no_file_mapping标记)大概利用写拷贝页面回护。在后一种情形下试图改动映像到文件的页面将招致在体系互换文件中天生页面拷贝。flush()办法将保留内存内数据库的映像光临时文件中然后利用原子操纵重定名到源文件。假如没有指定fault_tolerant标记,POST++在数据库页面上原有地位举行修正,供应最年夜的使用功能(由于没有拷贝修正页面和保留数据库映像光临时文件的分外开支)。在修正页面没有立即革新到磁盘的前提下,部分改动大概由于体系毛病而丧失(最坏的事是部分修正的页面保留了而别的一些没有保留-如许数据库的分歧性大概被搅乱了)。do_garbage_collection当设置了这个属性时POST++将在翻开贮存器时实行渣滓搜集。渣滓搜集操纵和指针对齐接洽在一同。利用渣滓搜集常常比手工内存开释来的平安(思索到挂起的援用成绩),可是显式内存开释开支较少。POST++中的渣滓搜集比拟显式内存分派有一个更年夜的上风:内存搜集器对小工具利用的页面举行优化。假如页中没有已分派的小工具那末渣滓搜集器将在余暇页中包括这一页。这不会在显式开释时完成,由于小工具的余暇单位被串成链不克不及复杂从这个链中移开(在渣滓搜集器中一切的链被从头机关)。即便你利用显式内存开释,我仍倡议你每隔必定工夫做渣滓搜集来反省援用的分歧性和没有内存泄露(garbage_collection办法前往开释工具的数量,假如你确信你已开释了一切的不克不及抵达的工具,那末这个值将会是0)。思索到渣滓搜集器修正存储中一切的工具(设置掩码位),重连链中余暇工具),在事件形式下运转GC多是损耗工夫和磁盘空间的操纵,由于一切文件中的页将被拷贝到事件纪录文件中)。
你能够经由过程file::max_file_size变量指定存储文件的最年夜尺寸。假如数据文件的巨细比file::max_file_size而且形式不是read_only,那末假造空间size_of_file-file::max_file_size之外的字节将被保存在文件映像空间的前面。当存储巨细扩大时(由于分派新工具),这些页面将被提交(在WindowsNT)并被利用。假如文件巨细年夜于file::max_file_size大概利用了read_only形式,那末映像地区的巨细和文件巨细分歧。在后一种情形下不成能举行存储扩大。在Windows中我利用GlobalMemoryStatus()办法来失掉关于体系实在可分派的假造内存的信息并削减file::max_file_size为该值。不幸我发明在Unix中没有笨重的挪用可用来到达不异的目标(getrlimit不前往用户历程可以使用的假造内存切实其实切信息)。
工具存储的接口在文件storage.h界说而且完成部分可在storage.cxx中看到。依附于操纵体系的映像内存文件的部分被封装在file类中,其界说在file.h完成在file.cxx.
POST++的安装
POST++的安装非常复杂。今朝在以下体系已过测试:DigitalUnix,Linux,Solaris,WindowsNT4.0,Windows95.我但愿关于年夜部分一切其他新Unix方言(AIX,HP-UX10,SCO...)也没有成绩。不幸的是我没偶然用过这些体系。在Windows下我利用MicrosoftVisualC++5.0和Borland5.02compilers编译。VisualC++的Makefiel是makefile,BrolandC++的Makefile是makefile。
为利用POST++独一你必要的器材就是函数库(在Unix下是libstorage.a在Windows下是andstorage.lib)。这个库能够经由过程运转make命令天生。有个出格的MAKE.BAT用于MicrosoftVisualC++,它利用makefile.mvc作为输出挪用NMAKE(假如你正在利用Borland请编纂这个文件大概经由过程make.exe-fmakefile.bcc命令挪用)。
在Unix下的安装能够经由过程拷贝POST++库和同文件到一些尺度体系目次上去完成。你必需为makefile里INSTALL_LIB_PATH和INSTALL_INC_PATH变量设置得当的值并运转makeinstall命令。INSTALL_LIB_PATH的缺省值为/usr/local/libINSTALL_INC_PATH的是/usr/local/include。你能够经由过程明白指定路径到POST++目次来编译和链接而制止拷贝文件到体系目次中。
POST++类库
POST++包含一些耐久类的界说,她们能够用于你的使用也能够作为开辟POST++类的好例子。你能够瞥见那些类的完成中乃至没有POST特定的代码。这些类包含array(数组),matrix(矩阵),string(字符串),L2-list(L2-列表),hashtable(哈希表),AVL-tree(AVL-树),R-tree(R-数),textobject(文本工具).R-tree供应了供应空间工具(包括空间对等物的工具)的疾速会见。文本工具包括了BoyerandMoore算法的修改,扩大到由OR/AND干系组合的多款式搜刮。这些类的界说能够在以下文件中发明:
形貌接话柄现Arraysofscalarsandreferences,matrixesandstringsarray.harray.cxxL2-listandAVL-treeavltree.havltree.cxxHashtablewithcollisionchainshashtab.hhashab.cxxR-treewithquadraticmethodofnodessplittingrtree.hrtree.cxxT-tree(combinationofAVLtreeandarray)ttree.httree.cxxTextobjectwithmodifiedBoyerandMooresearchalgorithmtextobj.htextobj.cxx
在论文"Astudyofindexstructuresformainmemorydatabasemanagementsystems"中T.J.LehmanandM.JCarey发起利用T-trees作为次要内存数据库的一个存储的无效的数据布局。T-trees基于AVL树由Adelson-VelskyandLandis发起。在这个分段中,我们供应T-trees一个概览作为在POST++中的完成。
像AVL树一样,T-tree的左子树和右子树高度差不年夜于1。和AVL树纷歧样,T-tree的每个节点分列序次保留多个关头值而不是单一关头值。一个节点里最右边和最右侧关头值界说包括在这个节点内关头值的局限。如许,一个节点左子树只包括比最左关头值小的关头值,而右子树包括比该节点最右关头值年夜的关头值。节点内落在最小和最年夜关头值之间的关头值被称作被该节点束缚(bounded)。注重即是最年夜关头字或最小关头字的关头字能够依据索引是不是全局独一和查找前提以为是被束缚或不被束缚(e.g.“年夜于”("greater-than")相对“年夜于即是”("greater-thanorequal-to"))。
一个既有左子树也有右子树的节点被回为外部节点(internalnode),唯一一个子树的节点被回为不完整叶(semi-leaf),一个没有子树的节点被回为叶(leaf)。为了坚持高占用率,每一个外部节点具有一个必需包括的关头值的最小数量(通常是k-2,假如k是能够分列在一个节点里的关头字的最年夜数量)。但是,关于叶子和不完整叶来讲没有占用率前提。
在T-tree中查找相称于间接查找。关于每个节点,反省看一下关头值是不是在该节点最左和最右关头值之间;假如是这类情形,就是说节点里包这个关头值的话就前往该值(不然关头值不包括在树中)。不然,假如关头值比最左关头值小,那末查找左子树,反之搜刮右子树。反复这个历程直到发明这个关头值大概查找到null节点。
在T-tree中拔出和删除略微庞大一些。关于拔出操纵,起首利用下面的搜刮历程来查找束缚拔出关头值的节点。假如存在如许的节点,那末节点中有空余的话关头值被拔出到这个节点中。假如节点中没有空余,那末关头值被拔出到节点中,该节点的最左关头值被拔出到该节点的左子树中(假如左子树为空,就分派一个新的节点把最左关头值拔出)。假如没有发明束缚节点,那我们用N来暗示搜刮失利的最初碰到的节点并按下述步骤持续:假如N有空余,那末关头值就拔出到N中;不然,关头值将被拔出到一个新节点并依据关头值和最左关头值和最右关头值作为N的右或左子节点/树。
删除关头值从判断包括关头值的节点入手下手,并从节点中删除关头值。假如删除关头值后剩下一个空的叶结点,那末节点也被删除。假如删除后剩下一个外部节点大概不完整叶个中包括比最小数目少的关头值,那末不敷的将经由过程挪动左子树中最年夜的关头值到节点中大概兼并节点和右子树来增补。
不管拔出仍是删除,分派/开释节点大概招致树不屈衡和举行扭转操纵(RR,RL,LL,LR)。(上面的形貌中子树的高度包含了拔出和删除的影响。)在拔出情形下,反省沿着新分派节点入手下手的节点到根节点的节点直到
发明一个节点有两个等高的子树(在这类情形下不必要扭转了),大概发明一个节点的左子树和右子树有年夜于1的分歧高度并实行包括节点的单一扭转。
在删除情形下,反省沿着开释节点的怙恃入手下手到根节点的节点直到发明一个节点它的子树高度相差1。并且每次碰到一个节点的子树的高度相差年夜于1时,举行一次扭转。注重开释一个节点大概招致屡次扭转。
有几个测试程序来测试POST++耐久类库中的类,他们被包括在缺省的make方针中:
ProgramTestedclassestesttree.cxxAVL-tree,l2-node,hashtabletesttext.cxxtext,stringtestspat.cxxrectangle,R-tree,hashtabletestperf.cxxT-treeinsert,findandremoveoperations
和POST++一同利用STL类
从POST++存储器中保留和获得STL类是大概的。POST++供应了出格的STL分派子偏重载了new/delete操纵符来坚持STL工具。有几个使得STL耐久的模子,经由过程以下几个宏来把持:
USE_MICROSOFT_STL利用MicrosoftSTL类,随MicrosoftVisualC++一同附带。这个类库和C++STL尺度不完整兼容。USE_STD_ALLOCATORS利用和C++尺度中一样的分派子。分派子工具包括在STL工具中,分派子工具中的实例办法用于分派/开释空间。以是有大概实行一个“伶俐的”分派子:仅在工具包括这个分派子的情形下分派子才为POST++存储器中的工具分派空间并且这个分派子也放在存储器中。不然,工具所占空间将经由过程尺度malloc()函数这个一般路子来分派。这个选项能够和SGISTL库和MicrosoftSTL库一同利用。注重依从尺度的SGISTL分派子利用了很多没有普遍完成的言语特征。出格是,他们依附于成员模板,部分特别化,部分分类(排序)的办法模板,typename关头字,和利用template关头字来援用依附范例的模板成员。以是在指定这个宏界说时只要多数C++编译器能够编译SGISTL库。假如没有设置这个宏,那末POST供应一个含有静态成员函数的分派子而且一切工具都从POST++存储器平分配。利用这个分派子的使用一次只能翻开一个POST++存储器。REDEFINE_DEFAULT_ALLOCATOR有两个路子使得STL工具耐久,一个路子是引进新范例:
typedefbasic_string<char,char_traits<char>,post_alloc<char>>post_string;
别的一个路子是使一切类具有耐久才能。当界说了REDEFINE_DEFAULT_ALLOCATOR宏,任何STL类能够在POST++存储器平分配。为了在耐久存储器中创立新工具,你必需指定存储器作为new操纵符分外的参数。假如存储器被疏忽,那末工具将利用尺度malloc()函数。
POST++到STL的接口不必要任何STL类的改动,以是你可使用你想实行的任何STL。可是作为一个了局,STL类不包括范例形貌以是POST++没有STL工具的格局信息。以是POST++不克不及够举行渣滓搜集和援用对齐。当利用了STL接口时,POST++存储器必需一直镜像到不异的假造地点上。假如你传送storage::fixed标记到storage::open(intflags)办法,那末假如不克不及镜像存储器到不异的内存地点POST++将呈报毛病而且前往false。假如你的使用只利用了一个存储器而且不镜像其他工具到假造内存中,那末几近一切的操纵下都大概镜像存储器到不异的内存地点。
POST++到STL库的接口界说在在头文件post_stl.h中。这个文件必需包括在任何STL包括文件中。一样宏REDEFINE_DEFAULT_ALLOCATOR,USE_STD_ALLOCATORS和USE_MICROSOFT_STL被在post_stl.h之前界说。
POST++包括利用STL++类的例子stltest.cxx。这个例子利用两个STL类-string和vector。从尺度输出读出去的行被压进到vector中而且程序被再次启动一切的vector的元素被打印到尺度输入上。这个例子被包括在为MicrosoftVisualC++设置的makefile的缺省方针中(其利用VC中附带的MicrosoftSTL类)。你也能够实验用其他版本的STL库来构建这个测试可是不要健忘关于REDEFINE_DEFAULT_ALLOCATOR和USE_STD_ALLOCATORS宏。这个例子一样能够和SGISTLport3.12和GCC2.8.1一同测试。
交换尺度分派子
在后面一节中我注释了怎样和STL库一同利用POST++。可是仍旧有良多其他你想用的C++和C库和使用,并且没有供应象STL这类易通融的分派机制。在这类情形下独一大概的办理计划(假如你不想改动此库的任何源代码的话)就是用一个POST++供应的来交换尺度的分派机制。如许任何静态分派工具都从POST++存储器平分配(除一个不克不及在这类情形下利用的存储器)。
POST++刊行包中包括的文件postnew.cxx重界说了尺度的malloc,free,realloc和calloc函数。当翻开存储器时,一切的工具被在存储器平分配。不然sbrk()函数被用来分派工具(为这些工具分派的空间没有接纳)。大概不必要打仗这些尺度C分派函数而仅需重载缺省的C++操纵符new和delete。当编译postnew.cxx时界说DO_NOT_REDEFINE_MALLOC宏来这么做。从postnew.cxx天生的方针文件必需在尺度C库前传送给链接程序。
作为一个POST++如许利用的例子能够拜见testnew.cxx和testqt.cxx。第一个举例申明了尺度C++数组怎样耐久化。第二个举例申明了POST++怎样和Qt类库一同事情。
就POST++没有关于存储类的格局信息这里有一些限定在POST++的利用上:
包括虚函数的类不被撑持(POST++不克不及准确的初始化到虚函数表的指针)。隐式内存开释(渣滓搜集器)是不成能的-POST++没有关于工具外部指针地位的信息。存储器必需总映照到不异的假造地点上由于假如基地点改动了POST++不克不及调剂指针。
假如一切这些限定不是你的使用所必须的,你可使其耐久化而不必要任何代码的修改。这个办法在C和C++程序中都可使用。
怎样利用POST++
这里有几个POST++类和使用的例子。个中最复杂的就是游戏“猜植物”。这个游戏的算法十分复杂而且了局看起来给人以深入的印象(有些象野生智能)。别的这个游戏是一个十分好的例子,分析了耐久工具存储的优点。这个游戏的源代码在文件guess.cxx中。创立这个游戏包括在缺省的make方针中。实行guess来运转它。
Unixspecific:当你筹办和POST++库链接你的Unix使用而且耐久工具中波阿含虚函数,请不要健忘重编译comptime.cxx文件并包括在链接列表中。这个文件是必需的用于POST++供应可实行文件的工夫戳,被放在存储器顶用来判断甚么时分使用被改动并在必要的时分从头初始化工具内的虚函数表。Attention!这个文件必需在你每次从头链接你的使用时被从头编译。我倡议你让编译器为你挪用链接程序并包括comptime.cxx源文件在为运转映像方针文件供应的工具文件列表中(seemakefile)。
调试POST++使用的细节
这一节的内容对利用了事件的使用长短常成心义的。POST++利用页面回护机制来供应当源页面修正时天生影子页面,当存储器翻开或事件提交时一切文件页面的映像是只读回护的。以是任何试图修正分派在这些页面里工具的内容将招致一个会见背例非常。这个非常被指定的POST++句柄处置。可是假如你利用调试器,它将起首捕捉这个非常并中断使用程序。假如你想调试你的使用你必需作一些筹办:
在Unix能够充实的告知调试器不要捕捉SIGSEGV旌旗灯号。好比关于GDB它能够经由过程命令来完成:handleSIGSEGVnostopnoprintpass。假如SIGSEGV旌旗灯号不是由存储页面回护背例发生,可是是程序中的一个毛病,POST++非常处置程序将“了解”它不是本人的非常并送出一个SIGABRT旌旗灯号到己历程中,这能够被调试器捕捉。在WindowsPOST++利用不处置非常过滤器来(UnhandledExceptionFilter)处置存储器页面回护背例。不幸的是不成能让MicrosoftDebugger疏忽不处置非常。假如你筹办调试你的使用,你必需把一切你的程序代码(main大概WinMain函数)封装为布局化的非常堵塞。你必需在BorlandC++中总利用布局化非常处置,由于UnhandledExceptionFilter没有在Borland中被准确挪用。请利用两个宏SEN_TRY和SEN_ACCESS_VIOLATION_HANDLER()来封装main(或WinMain)的函数体:
main(){SEN_TRY{...}SEN_ACCESS_VIOLATION_HANDLER();return0;}
请断定调试器对此非常的举动是“假如没有处置就中断”而不是“老是中断”(你能够在Debug/Exceptions菜单中反省它)。在文件testrans.cxx中你能够发明利用布局化非常处置的例子。
关于POST++的更多的一些信息
POST++是freeware。开辟出她但愿是有效的。经由过程她你能够做任何你想做的(在开辟产物中利用POST++没有任何限定)。我将很乐意来匡助你利用POST++和失掉关于POST++任何范例的信息(毛病呈报,倡议...)。POST++的收费软件情况其实不意味着短少撑持。我包管将勉力修改任何呈报的毛病。也供应e-mail撑持。POST++有几种用处:在分歧时代保留信息,在文件中保留工具体系,快照,信息体系...可是假如你感应你必要在你的使用利用更主要的面向工具数据库以供应并发,散布式和事件处置,请会见GOODS(GenericObjectOrientedDatabaseSystem)homepage。
Lookfornewversionatmyhomepage|E-mailmeaboutbugsandproblems
任何规模的组织都可能受益于外包服务,并在一个标准化和优化的平台上统一其数据库管理任务。基于其本身的特性,DBaaS提供了敏捷和高效的数据库服务,它可以支持多变的需求。 |
|