zoukankan      html  css  js  c++  java
  • C++中的POD型别

      最近在阅读《STL源码刨析》的过程中,遇到了POD型别,书中的解释是: 

      POD意指Plain Old Data,也就是标量型别(scalar types)或传统的C struct型别。POD型别必然拥有trivial ctor/dctor/copy/assignment operator函数。(这里的trivial 函数意思是该函数无光痛痒,不重要,即平凡函数)

      但是看完这个解释,我还是没有很清楚的理解所谓POD型别,通过在网上查阅资料,我对POD有了更好的理解。网上讲到一种判断POD型别的方式,即当一个数据类型同时满足”平凡的定义“和”标准布局“,我们可以认为其是一个POD型别的数据。

    平凡的定义

    平凡的结构体

      对于一个类或结构体来讲,平凡的定义是:

    • 平凡的构造/拷贝构造/移动构造函数
    • 平凡的拷贝复制/移动复制运算符
    • 平凡的析构函数
    • 不包含虚函数、虚基类

      测试代码:

    #include<iostream>
    using namespace std;
    
    class A { A() {} };                        //自定义构造函数
    class B { B(B&) {} };                    //自定义拷贝构造函数
    class C { C(C&&) {} };                    //自定义移动构造函数    
    class D { D operator=(D&) {} };            //自定义拷贝赋值运算符    
    class E { E operator=(E&&) {} };        //自定义移动复制运算符
    class F { ~F() {} };                    //自定义析构函数
    class G { virtual void foo() = 0; };    //含有虚函数
    class H : G {};                            //继承自纯虚类
    class I {};
    
    int main()
    {
        std::cout << "有不平凡的构造函数" << ends << std::is_trivial<A>::value << std::endl;        
        std::cout << "有不平凡的拷贝构造函数" << ends << std::is_trivial<B>::value << std::endl;
        std::cout << "有不平凡的移动构造函数" << ends << std::is_trivial<C>::value << std::endl;
        std::cout << "有不平凡的拷贝赋值运算符" << ends << std::is_trivial<D>::value << std::endl;
        std::cout << "有不平凡的移动赋值运算符" << ends << std::is_trivial<E>::value << std::endl;
        std::cout << "有不平凡的析构函数" << ends << std::is_trivial<F>::value << std::endl;        
        std::cout << "有虚函数" << ends << std::is_trivial<G>::value << std::endl;        
        std::cout << "有虚基类" << ends << std::is_trivial<H>::value << std::endl;            
        std::cout << "平凡的类" << ends << std::is_trivial<I>::value << std::endl;            
    
        system("pause");
        return 0;
    
    }

    运行结果:

    测试环境:VS2019

    平凡的函数

      这里所提到的平凡的构造、析构函数,就是指编译器自动生成的构造、析构函数等,也就是说一个POD型别的数据是不能有用户自定义的构造/拷贝构造/移动构造函数,拷贝复制/移动复制运算符以及析构函数。

    标准布局的定义

    • 所有非静态成员有相同的访问权限
    • 继承树中最多只有一个类有非静态数据成员
    • 子类的第一个非静态成员不可以是基类类型
    • 没有虚函数、虚基类
    • 所有非静态成员都符合标准布局类型

    测试代码:

    #include <iostream>
    using namespace std;
    
    //成员a和b具有不同的访问权限
    class A
    {
    private:
        int a;
    public:
        int b;
    };
    //继承树有两个(含)以上的类有非静态成员
    class B1
    {
        static int x1;
    };
    
    class B2
    {
        int x2;
    };
    
    class B : B1, B2
    {
        int x;
    };
    //第一个非静态成员是基类类型
    class C1 {};
    class C : C1
    {
        C1 c;
    };
    //有虚函数
    class D { virtual void foo() = 0; };
    //有虚基类
    class E : D {};
    //非静态成员x不符合标准布局类型
    class F { A x; };
    
    int main()
    {
        std::cout << std::is_standard_layout<A>::value << std::endl;  // 违反定义1。成员a和b具有不同的访问权限
        std::cout << std::is_standard_layout<B>::value << std::endl;  // 违反定义2。继承树有两个(含)以上的类有非静态成员
        std::cout << std::is_standard_layout<C>::value << std::endl;  // 违反定义3。第一个非静态成员是基类类型
        std::cout << std::is_standard_layout<D>::value << std::endl;  // 违反定义4。有虚函数
        std::cout << std::is_standard_layout<E>::value << std::endl;  // 违反定义5。有虚基类
        std::cout << std::is_standard_layout<F>::value << std::endl;  // 违反定义6。非静态成员x不符合标准布局类型
    
        system("pause");
        return 0;
    }

    运行结果:

    测试环境:VS2019

    POD型别的作用

      为什么C++需要引进POD这一个概念?我结合自己的理解和网上的资料总结出以下几点:

    • POD型别是兼容传统的C struct的,在需要与C语言交接的地方起作用
    • 提升效率。《STL源码剖析》中讲到,如果一个数组的成员是POD型别的数据,那么在对该数组进行拷贝操作的时候,可以直接调用更为底层的函数进行操作,而不需要对每一个成员使用复制赋值构造函数
    • 一个POD型别的类或结构体通过二进制拷贝后还能保持其数据不变
  • 相关阅读:
    [Misc ]bw 注入过程 150
    [Misc]2015 RCTF 日志记录
    [课堂笔记]铁三Linux取证
    [Web] 赛博地球杯 源码泄露
    ROPgadget 工具
    一步一步学ROP之linux x86 学习笔记
    Linux环境崩溃生成core文件以及调试
    文件头文件尾总结
    Linux (x86) Exploit Development Series 阅读笔记level1 Classic Stack Based Buffer Overflow
    Python 进制转换
  • 原文地址:https://www.cnblogs.com/honernan/p/13161775.html
Copyright © 2011-2022 走看看