转 PIMPL

发布时间:2019-08-06 发布网站:脚本宝典
脚本宝典收集整理的这篇文章主要介绍了转 PIMPL脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。

RaiI 与Pimpl 地址http://tech.uc.cn/?p=851

RAII

RAII是Bjarne Stroustrup教授用于解决资源分配而发明的技,资源获取即初始化。

RAII是C++的构造机制的直接使用,即利用构造函数分配资源,利用析构函数来回收资源。

我们知道,在C/C++语言中,对动态分配的内存的处理必须十分谨慎。在没有RAII应用的情况下,如果在内存释放之前就离开指针的作用域,这时候几乎没机会去释放该内存,除非垃圾回收器对其管制,否则我们要面对的将会是内存泄漏

举个例子来说明下RAII在内存分配方面的使用。

转 PIMPL

这是典型的C风格代码,没有应用RAII。
因此值得注意的是,destroy_bytearray必须在退出作用域前被调用。
然而在复杂的逻辑设计中,程序员往往要花大量的精力以确认所有在该作用域分配的ByteArray得到正确的释放。

相形之下,C++运行机制保证了栈上对象一旦即将离开作用域,其析构函数将被执行,给予了释放资源的时间。注意,在堆分配的对象必须调用delete来结束其生命。

转 PIMPL

C++11 STL中的std::unique_ptr可用于控制作用域中的动态分配的对象。
譬如:

转 PIMPL

函数bar()只是增加了一行,但强壮了很多,函数bar()执行完或者有异常抛出时,holder总会被析构,从而ba或被delete。

下面是ByteArray的Ada实现:

    -- lib.ads

    withinterfaces;

    withAda.@H_304_59@Finalization;

    packagelib is

        typeuchars isarray(positive range<>)ofinterfaces.unsigned_8;

        typeuchars_p isaccessuchars;

        typeByteArray isnewAda.Finalization.Limited_Controlled withprivate;

        functionCreate(length:integer)returnByteArray;

    private

        typeByteArray isnewAda.Finalization.Limited_Controlled withrecord

            length:integer;

            data:uchars_p;

        endrecord;

        overriding

        procedureInitialize(This:inoutByteArray);

        overriding

        procedureFinalize(This:inoutByteArray);

    endlib;



    -- lib.adb

    withAda.Unchecked_Deallocation;

    packagebodylib is

        useAda.Finalization;

        functionCreate(length:integer)returnByteArray is

        begin

            iflength<0then

                put_line("Create");

                returnByteArray'(Limited_Controlled with length => length,

                       data=> new uchars(1..length));

            end if;

            return ByteArray'(Limited_Controlled withlength=>0,data=>null);

        endCreate;

        overriding

        procedureInitialize(This:inoutByteArray)is

        begin

            put_line("Initialize");

            this.length:=0;

            this.data:=null;

        endInitialize;

        overriding

        procedureFinalize(This:inoutByteArray)is

            procedurefree isnewAda.Unchecked_Deallocation(uchars,uchars_p);

        begin

            put_line("Finalize");

            if(this.data/=null)then

                free(this.data);

            endif;

        endFinalize;

    endlib;



    -- main.adb

    withlib;

    uselib;

    proceduremain is

        K:ByteArray:=Create(10240);

        C:ByteArray;

    begin

        null;

endmain; 

– 输出如下
./main
Create
Initialize
Finalize
Finalize

另一种情况是对I/O资源的处理,当我们不再使用资源时,必须将资源归还给系统。
下面例子来自 wikipedia的RAII条目:

转 PIMPL

在write_to_file函数中,RAII作用于std::ofstream和std::lock_Guard,从而保证了函数write_to_file在返回时,lock和file总会调用自身的析构函数,对于lock而言,它会释放mutex,而file则会close。

Pimpl

Pimpl(pointer to implementation),是一种应用十分广泛的技术,它的别名也很多,如Opaque pointer, handle classes等。

wikipedia上已经对其就Ada、C和C++举例,这里不作举例。
个人认为,Pimpl是RAII的延展,籍由RAII对资源的控制,把具体的数据布局和实现从调用者视线内移开,从而简化API接口,也使得ABI兼容变得有可能,Qt和KDE正是使用Pimpl来维护API的一致性,另外也为惰性初始化提供途径,以及隐式共享提供了基础。

我在设计代码时也会考虑使用Pimpl,但不是必然使用,因为Pimpl也会带来副作用,主要有两方面

  • Pimpl指针导致内存空间开销增大

  • 类型间Pimpl的访问需要较多间接的指针跳转,甚至还用使用friend''来提升访问权限,如以下代码中,Teacher可以访问Student的Context。

    转 PIMPL

尽管如此,我个人还是在面向开发应用的接口中会尽量使用Pimpl来维护API和ABI的一致性,除非Pimpl会引起显著的性能下降。

脚本宝典总结

以上是脚本宝典为你收集整理的转 PIMPL全部内容,希望文章能够帮你解决转 PIMPL所遇到的问题。

如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典推荐好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。