精华内容
下载资源
问答
  • 2021-03-10 13:06:57

    如果用户不定义析构函数,而是用系统自带的,则说明,析构函数基本没有什么用(但默认会被调用)我们称之为trivial destructor。反之,如果特定定义了析构函数,则说明需要在释放空间之前做一些事情,则这个析构函数称为non-trivial destructor。如果某个类中只有基本类型的话是没有必要调用析构函数的,delelte p的时候基本不会产生析构代码,在C++的类中如果只有基本的数据类型,也就不需要写显式的析构函数,即用默认析构函数就够用了,但是如果类中有个指向其他类的指针,并且在构造时候分配了新的空间,则在析构函数中必须显式释放这块空间,否则会产生内存泄露,在STL中空间配置时destory()函数会判断要释放的迭代器的指向的对象有没有trivial destructor(STL中有一个 has_trivial_destructor函数,很容易实现检测),如果有trivial destructor则什么都不做,如果没有即需要执行一些操作,则执行真正的destory函数。

    下面是一个例子,不记得在哪里看到了,一直保存在电脑上,是转载的。

    项目中有一些地方为了得到较快的速度,使用了无需释放的简易内存分配器:先一次分配一大块内存,然后每次需要内存的时候从这块内存里面直接递增分配合适大小的内存块。当使用完这些内存了以后,不做显式的释放,直到整个大任务结束了以后,才一次释放那整块内存。这样做优点在于

    • 内存分配非常快速,仅仅递增指针即可
    • 没有释放的开销(除了整块释放)
    • 不会有碎片

    这种做法是很多引擎的常见选择。但是也有一个很大的缺陷,就是每个分配对象的析构函数并没有被调用。当然我们在释放所有内存的时候也可以试图调用所有的对象的析构函数,不过出于效率考虑,很多引擎并没有在所有的模块里进行析构函数的调用,尤其是一些POD(plain old data),不调用析构函数也明显无害。当然,这样就留下了隐患。

    根据墨菲定理,不想发生的事情,最终总会发生。最近项目就遇到了这样的情况。

    先是大家发现有很快速的内存泄漏,不巧的是,正好引擎的内存监测系统年久失修,本来可以秒杀的问题,由于内存监测系统的罢工,导致无法被快速定位。

    手工人力定位,最后发现,问题就出在我们省略的析构函数调用上。

    原来,新来的同事扩展了原来的POD结构,在POD里面加上了资源分配,现在这就不是POD了,变成标准的类,顺理成章的,他也添加了析构函数,在里面释放新分配出来的资源。问题就在于,这个类型是用前述的快速分配系统创建出来的,析构函数从我们设计之初就没打算调用,这样分配的资源无法释放,造成了泄漏。

    对于这样有隐患的系统,的确无法继续容忍,但我们也不打算为这样的例外牺牲效率,对所有快速分配系统调用析构函数。所以问题的核心,就变成了我们是否能够检测的这种情况了。

    解决问题的想法是,我们能否检测到这个情况,如果能在编译时刻检测到这一情况,我们就可以报错,或者用模版来产生不同的代码,从而对POD沿用旧的机制,没有额外的开销,其他类则自动调用析构函数。

    进一步简化问题,我们如果能确定一个类有non-trivial destructor,我们就要在释放的时候对这些对象调用析构函数。google了一下,原来stl里面就有一个std::has_trivial_destructor,大喜,使用,果然有用,用这个模板类可以检测出一个类有没有non-trivial destructor。这样就很容易能实现编译时刻的类型检测,从而产生报警或是模版类处理析构情况。

    由于项目中使用的是eastl,就原样替换成eastl的has_trivial_destructor,发现失败了。。。原来eastl只支持检测一个类型是否是pod,但是这个pod检测也不准。。。放了一个pod的struct,居然说不是pod。看了eastl代码,发现注视里面提到,考虑到跨平台的问题,说只能做到那样了。。。但是vc自带stl是可以工作的,再去看VC stl实现代码,vc的stl可读性太差了。。。都是各种宏替换。遂使用编译器预处理cpp文件,产生了一个.i文件,看了一下,里面检测non-trivial destructor的地方调用了一个__has_trivial_destructor。这个东西有意思,据我所知一般vc里面__开头的函数都是intrinsic函数。查了msdn,真是vc自己扩展的,还顺藤摸瓜,查到了其他一堆检测c++类型的intrinsic函数。

    问题迎刃而解,只要用vc的扩展函数就可以搞定了。但是这东西牺牲了跨平台性,也算双刃剑。

    更多相关内容
  • 默认constructor的删除,构建自己的constructor,destructor调用

    constructor

    class类有自己默认的constructor,方法体为空。当我们构建自己的constructor后,默认constructor失效,也可以手动删除默认constructor。

    //删除默认constructor,构建自己的constructor
    class Player
    {
    private:
    	int PlayerX,PlayerY;
    public:
    	Player() = delete;
    	Player(int x,int y){
    		PlayerX = x;
    		PlayerY = y;
    	}
    }
    
    int main(){
    	Player player(1,1);
    }
    

    destructor

    类的destructor在main结束后,会自动调用destructor,若手动调用destructor,main函数结束还是会再次调用destructor

    class Player
    {
    private:
    	int PlayerX,PlayerY;
    public:
    	Player() = delete;
    	Player(int x,int y){
    		PlayerX = x;
    		PlayerY = y;
    	}
    	
    	~Player(){
    		...
    	}
    }
    
    int main(){
    	Player player(1,1);
    	player.~player();
    }
    
    展开全文
  • C++ 虚拟析构函数 (virtual destructor)

    千次阅读 多人点赞 2021-05-15 07:19:47
    C++ 虚拟析构函数 (virtual destructor). 虚拟析构函数的用法以及使用场景.

    C++ 虚拟析构函数

    概述

    虚析构函数 (virtual destructor) 可以帮我们实现基类指针删除派生类对象.

    在这里插入图片描述

    问题

    当我们从派生类的对象从内存中撤销时会先调用派生的析构函数, 然后再基类的析构函数, 由此就会产生问题:

    • 如果用 new 运算符建立了派生类对象, 并且由一个基类的指针比那里指向该对象
    • 用 delete 运算符撤销对象时, 系统只执行基类的析构函数. 而不执行派生类的析构函数, 派生类对象析构中要求的工作将被忽略

    Base 类:

    #ifndef PROJECT6_BASE_H
    #define PROJECT6_BASE_H
    
    #include <iostream>
    using namespace std;
    
    class Base {
    public:
        Base() {
            cout << "执行基类构造函数" << endl;
        };
        ~Base() {
            cout << "执行基类析构函数" << endl;
        };
    };
    
    #endif //PROJECT6_BASE_H
    

    Derived 类:

    #ifndef PROJECT6_DERIVED_H
    #define PROJECT6_DERIVED_H
    
    #include <iostream>
    #include "Base.h"
    using namespace std;
    
    class Derived : public Base {
    public:
        Derived() {
            cout << "执行派生类构造函数" << endl;
        };
        ~Derived() {
            cout << "执行派生类析构函数" << endl;
        }
    };
    
    #endif //PROJECT6_DERIVED_H
    

    main:

    #include <iostream>
    #include "Derived.h"
    using namespace std;
    
    int main() {
    
        Base *pt =new Derived;
        delete pt;
    
        return 0;
    }
    

    输出结果:

    执行基类构造函数
    执行派生类构造函数
    执行基类析构函数
    

    虚析构函数

    当基类的析构函数为虚函数时, 无论指针指的是同一族中的哪一个类对象, 系统会采用动态关联, 掉啊用相应的析构函数, 对该对象进行清理工作. 即先调用了派生类的析构函数, 再调用了基类的析构函数.

    Base 类:

    #ifndef PROJECT6_BASE_H
    #define PROJECT6_BASE_H
    
    #include <iostream>
    using namespace std;
    
    class Base {
    public:
        Base() {
            cout << "执行基类构造函数" << endl;
        };
        virtual ~Base() {
            cout << "执行基类析构函数" << endl;
        };
    };
    
    #endif //PROJECT6_BASE_H
    

    Derived 类:

    #ifndef PROJECT6_DERIVED_H
    #define PROJECT6_DERIVED_H
    
    #include <iostream>
    #include "Base.h"
    using namespace std;
    
    class Derived : public Base {
    public:
        Derived() {
            cout << "执行派生类构造函数" << endl;
        };
        ~Derived() {
            cout << "执行派生类析构函数" << endl;
        }
    };
    
    #endif //PROJECT6_DERIVED_H
    

    main:

    #include <iostream>
    #include "Derived.h"
    using namespace std;
    
    int main() {
    
        Base *pt =new Derived;
        delete pt;
    
        return 0;
    }
    

    输出结果:

    执行基类构造函数
    执行派生类构造函数
    执行派生类析构函数
    执行基类析构函数
    

    总结

    如果将基类的析构函数声明为虚函数时, 由该基类所派生的所有派生类的析构函数也都自动成为虚函数. 即使派生类的析构函数与其基类的构造函数名字不相同.

    最好把基类的析构函数声明为虚函数. 即使基类并不需要析构函数, 我们也可以定义一个函数体为空的虚析构函数, 以保证撤销动态分配空间能正确的处理.

    注: 构造函数不能声明为虚函数.

    展开全文
  • Cookie DestrucTor-开源

    2021-05-03 16:37:31
    Cookie DestructoR可帮助您维护网络隐私。 该软件具有即时清除Cookie和Internet缓存的功能。 如有必要,可以销毁计算机上的Index.dat数据库文件。
  • game-destructor:由GitHub Classroom创建的game-destructor
  • gem 'destructor' 然后执行: $ bundle 或者自己安装: $ gem install destructor 用法 require 'destructor' class Foo attr_reader :bar def initialize @bar = 123 end def finalize puts ...
  • 运行程序,程序出现崩溃 (偶然崩溃),看一了一下崩溃信息,如下: createLink::'scalar deleting destructor' (unsigned int) 他是什么错误啊?
  • Computer Destructor-开源

    2021-06-08 17:42:00
    这是你应该完全拥有它的最棒的 pwogwam eva! 啊啊啊啊
  • GCC可以给函数若干属性,其中constructor就是其中一个。具体有哪些属性,可以看GCC的文档。 公共属性:... ... 在上面文档中有对于constructor与destructor的描述: ..

    GCC可以给函数若干属性,其中constructor就是其中一个。具体有哪些属性,可以看GCC的文档。

    公共属性:https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#Common-Function-Attributes

    所有属性:http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html 

    在上面文档中有对于constructor与destructor的描述: 

    引用

    constructor

    destructor

    constructor (priority)

    destructor (priority)

    The constructor attribute causes the function to be called automatically before execution enters main (). Similarly, the destructor attribute causes the function to be called automatically after main () completes or exit () is called. Functions with these attributes are useful for initializing data that is used implicitly during the execution of the program.

    On some targets the attributes also accept an integer argument to specify a priority to control the order in which constructor and destructor functions are run. A constructor with a smaller priority number runs before a constructor with a larger priority number; the opposite relationship holds for destructors. So, if you have a constructor that allocates a resource and a destructor that deallocates the same resource, both functions typically have the same priority. The priorities for constructor and destructor functions are the same as those specified for namespace-scope C++ objects (see C++ Attributes). However, at present, the order in which constructors for C++ objects with static storage duration and functions decorated with attribute constructor are invoked is unspecified. In mixed declarations, attribute init_priority can be used to impose a specific ordering.

    Using the argument forms of the constructor and destructor attributes on targets where the feature is not supported is rejected with an error.


            大致意思就是,可以给一个函数赋予constructor或destructor,其中constructor在main开始运行之前被调用,destructor在main函数结束后被调用。如果有多个constructor或destructor,可以给每个constructor或destructor赋予优先级,对于constructor,优先级数值越小,运行越早(优先级 0 到 100 为实现所保留,所以最小为101)。destructor则相反,优先级数值越小,运行越晚(优先级 0 到 100 为实现所保留,所以最小为101)。 
    下面是一个例子: 

    C代码  收藏代码

    #include <stdio.h>
     
    void begin(void) __attribute__((destructor(103)));
    void end(void) __attribute__((destructor(102)));
     
    int main(void)
    {
            printf ("\nInside main()\n");
    
            return 0;
    }
    
    void begin(void)
    {
            printf ("\nIn begin()\n");
    }
    
    void end(void)
    {
            printf ("\nIn end()\n");
    }
    


       
      运行的结果为: 

    Inside main()

    In begin()

    In end()

    reference:https://blog.csdn.net/xiaofei125145/article/details/52597256

    展开全文
  • ~ClxDerived() { cout << "Output from the destructor of class ClxDerived!" ; }; void DoSomething() { cout !" ; };};  代码 ClxBase *pTest = new ClxDerived;pTest->DoSomething();delete pTest; ...
  • 丑如罪 的mod,添加了各种可选功能和机制。 最初以HD-Scavenger开头,专注于长期的“生存”功能,但后来Swift扩展为通用增强型mutator。 特征 通常将功能实现为具有各种可自定义设置的可切换模块。...
  • __attribute__((constructor)) 与 __attribute__((destructor)) 是 GCC 中用来修饰函数的,constructor 可以使被修饰的函数在 main() 执行前被调用,destructor 可以使被修饰的函数在 main() 执行结束或 exit() 调用...
  • scalar deleting destructor(unsigned int)

    千次阅读 2021-02-19 08:37:57
    在使用vs调试时,析构函数执行时在’scalar deleting destructor’的位置报错,怀疑是指针被delete了多次,但最后发现是”被释放的内存存在越界问题“,比较难发现。问题简要如下 class MemCorrupt { public: ...
  • 属性__attribute__((constructor)和__attribute__(((destructor)) __attribute__是可以修饰多个函数的,这给当然不例外。 但是需要注意的是执行顺序,同一属性的函数执行顺序似乎不太好确定。原因的话等什么时候看...
  • __attribute__((constructor)): 被该属性修饰的构造函数会在进入main函数之前被自动调用 __attribute__((destructor)):被该属性修饰的析构函数会在main函数完成或exit韩硕被调用后自动调用 此外该属性还接受一个...
  • 类的析构函数的外实现出错而产生了如下报错 ~queue::queue(){if(p) delete []p;} 正确写法: queue::~queue(){if(p) delete []p;}
  • 在全局声明了一个结构体,随即对其进行memset(),出现如题的报错信息。 C++中,全局域只能声明、初始化变量; 不能用于赋值、运算、调用函数 MY_STRUCT my_struct
  • 一个简单的库,可使用raii_with(resource, initializer, destructor) { ... } -syntax在符合标准的C99中提供RAII(或类似的东西raii_with(resource, initializer, destructor) { ... } : # include " raii/raii.h ...
  • error: expected constructor, destructor, or type conversion before ‘.’ token 找了半天原因,原来是犯了基础知识不扎实的错误,C++中,全局阈只能声明、初始化变量; 不能用于赋值、运算、调用函数等!!! 在...
  • c++中的 trivial destructor

    2019-03-16 16:04:12
    如果用户不定义析构函数,而是用系统自带的,则说明,析构函数基本没有什么用(但默认会被调用)我们称之为trivial destructor。反之,如果特定定义了析构函数,则说明需要在释放空间之前做一些事情,则这个析构函数...
  • C++中的trivial destructor 转:http://blog.csdn.net/wudishine/article/details/12307611   如果用户不定义析构函数,而是系统自带的,那么说明析构函数基本没什么用(但默认会被调用)。我们称之为trivial ...
  • Destructor_Application_1.0 适用于 Android 的自毁消息应用程序。
  • C++中的__has_trivial_destructor(typename) 最近学习《STL源码剖析》,实际看了stl头文件stl_construct.h,文件中看到有如下代码: template<typename _ForwardIterator> inline void _Destroy(_...
  • [C++] Virtual Destructor

    千次阅读 2018-05-04 12:44:17
    当删除指针时,如果指针的对象的静态类型不同于它的动态类型,那么:静态类型必须为基类,且基类必须定义 virtual destructor,否则行为就是未定义的。 而且,如果没有将基类的析构函数定义为 virtual, 当delete指针...
  • 因此,destructor 关注的首要问题就是内存的操作,不能越界销毁或重复销毁,也不能销毁不彻底,造成内存泄漏。 最佳实践 Best Practice 存在继承的情况下,base class 的 destructor 就声明为 virtual , 防止析构 ...
  • 今天写代码是遇到这样一个问题error: expected constructor, destructor, or type conversion before '.' token;立马网上查,原来是说不能再全局域进行不能用于赋值、运算、调用函数等,只能做变量的声明和初始化...
  • Bison之destructor

    2019-11-01 10:43:09
    因为我一开始以为,在每次销毁token的时候都会调用这个destructor。因为我的token有的会带有指针类型的值,但却并不是所有匹配规则都会用到这个指针指向的值。所以我以为只要设置了destructor,在每次匹配成功一个...
  • 写 C++ 的时候,如果前端是 Clang 那么当你定义静态全局变量时, 就可能会出现一个警告, 叫做 “exit-time destructor”。 作为一个习惯把警告当作错误看的骚年, 我果断去查了为什么会这样,而结果是这样的: ...
  • 析构函数(destructor

    千次阅读 2019-01-23 15:44:07
    析构函数(destructor) 与构造函数相反,当对象结束其生命周期,如对象所在的函数已调用完毕时,系统自动执行析构函数。析构函数往往用来做“清理善后” 的工作(例如在建立对象时用new开辟了一片内存空间,delete会...
  • warning: delete called on non-final 'xxx' that has virtual functions but non-virtual destructor 因为类中有纯虚函数。 只要纯虚函数, 就必须要虚析构函数。 所以解决办法就是在原类中定义虚析构函数。 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 44,042
精华内容 17,616
关键字:

destructor