说说C++中的POD

背景

POD的全称是Plain Old Data,这个Old就是体现了C语言的兼容。POD数据类型就是兼容性很重要的体现,特别是对用户自定义的类型(struct,class定义的类)。因为标准要求POD类型的内存布局是完全与C语言。

原理

C++是C的超集,加入了更多语法层面的新机制,编译器充当了一个翻译的角色


struct POD
{
    int v;
    int a;
};

struct NotPOD
{
    public:
        NotPOD(){}
    
        int v;
        int a;
};

上面的NotPOD结构体,表面上看只是比结构体POD多定义了一个构造函数。但当编译器将其翻译成汇编时,对NotPOD的构造函数,是产生了额外的代码(<< 深入探索C++对象模型 >>中有深入讲解),所以它的内存布局肯定跟POD结构体就不一样了。最典型的虚函数,是编译器产生一个VTABLE去实现,所以有虚函数的结构体必然不会跟C语言的内存布局一致。

所以在C++标准中定义的POD类型标准,其实就是编译器不会生成额外代码的准则。

POD类型

每个版本标准的POD类型都不一样,这也是C++ 的繁琐之处,作为C语言的超集,背负了兼容C语言的包袱,每次版本更新,这种兼容性语法必然会更新。其实作为一个开发者,应该不需要,也不应该去关注这些细节。这也是C++被诟病的地方。

POD类型的语法实在让人觉得繁琐,枯燥。这里介绍C++ 11中为POD类型(C++ 11标准是C++ 走向现代语言的一个重要标识)提供几个检测的模板类,再掌握几个简单经验,则足以写出 POD类型。

类型判断工具
  • template < typename T> struct std:: is_ pod;

这个工具直接判断类型T是否是POD类型,最常用,最有用

示例代码

#include <iostream>
struct D3
{
    D3()
    {
        a = 1;
        b = 1;
        c = 1;
        d = 1;
    }

    int a;
    int b;
    int c;
    int d;
};

struct D4
{
    int v;
    int a;
};


int main()
{

    std::cout << std::is_pod<D3>::value << std::endl;
    std::cout << std::is_pod<D4>::value << std::endl;
}
  • template < typename T> struct std:: is_ trivial;

判断是否平凡类型,这是C++ 11中对POD类型引入的一个新的概念,满足了trivial类型,才是POD类型

#include <iostream>
struct D3
{
    D3()
    {
        a = 1;
        b = 1;
        c = 1;
        d = 1;
    }

    int a;
    int b;
    int c;
    int d;
};

struct D4
{
    int v;
    int a;
};

int main()
{

    std::cout << std::is_trivial<D3>::value << std::endl;
    std::cout << std::is_trivial<D4>::value << std::endl;
}
几个经验
  1. C++中所有的基础类型(int,char,double,指针等类型)都是POD类型
  2. 基础类型的数组都是POD类型
  3. STL中的array为POD类型,其余的STL容器都是非POD类型
  4. 以struct来定义自定义类型。
  5. 不要定义构造,析构函数,复制构造函数,赋值函数,移动构造函数
  6. 不要定义类非静态方法
  7. 类的成员不要出现非POD类型
  8. 不要使用继承(随意在特定条件下,有继承的类型可以POD类型,但是建议还是不要使用,很容易出错)

综上几点,其实最简单,兼容最强(不同的编译器的内存布局的处理方法可能会不一样)的就是以C语言struct的方式使用struct(只有基本数据类型)。

一个比较典型的例子
#include <iostaream>
struct sTest
{
    std::string str;
    int v;
}

int main()
{
    sTest t;
    memset(&t,0,sizeof(sTest));
}

上面的代码,sTest不是POD类型,因为string不是POD类型。直接通过memset去初始化t对象,是会崩溃的。这是个很容易犯错误的地方,有些程序员,觉得STL中的string比C语言的char方便,所以在结构体使用string,然后还是以memset初始化。
在C++ 中,非POD类型是不能使用memset和memcpy函数的

POD类型的用处

  • 内存布局跟C语言一样,用于C 库的接口。
  • C++ 开发的库,对外提供的数据类型都应该是POD类型。尤其是用于C语言或.Net的C++库。
  • 可以直接用memeset初始化,或用memcpy拷贝
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

mo4776

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值