深入C++ 之逐位拷贝(bitwise copy)

深入C++ 之逐位拷贝(bitwise copy)

提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加
例如:第一章 Python 机器学习入门之pandas的使用


提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档

 


前言

    最近有重新翻阅的侯捷老师的《深度探索C++对象模型》一书,依然别有新意源源涌来,不禁感叹经典书籍的魅力,好了,话不多说,进入今天的正题--逐位拷贝(bitwise copy)。


提示:以下是本篇文章正文内容,下面案例可供参考

一、逐位拷贝(bitwise copy)是什么?

       众所周知的c++是兼容c语言的,而在传统的c语言中,顺序控制的语言执行结果,打造了内存位置与内容的完美对应,数据之间的赋值,可以通过内存的拷贝来完成。因为C语言中的类型,除了内置的类型之外,自定义的结构体类型struct的内存模型对我们来说,也是可知的。所以逐位拷贝存在于c语言中是美好的。但是c++语言本身是面向对象的语言,本身具有的多态性,对于程序员本身来讲,是不完全可知的,加上编译器对c++的优化,造成了不是所有的c++对象都适合逐位拷贝来实现c++对象之间的赋值拷贝操作。

二、POD(Plain Old Data)对象

1.什么是POD

       简单的讲,我们把c++中带传统C风格的数据类型叫做POD(Plain Old Data)对象,C的所有对象都是POD。POD对象的二进制是可以完美的赋值拷贝的,并且二进制数据可以还原出原POD对象。因此,在c++中可以利用像memset(),memcpy()这样的函数操作POD对象。

      那么什么样的类型是POD类型的呢?class、struct、union,且不具有用户定义的构造函数、析构函数、拷贝算子、赋值算子;不具有继承关系,因此没有基类;不具有虚函数,所以就没有虚表;非静态数据成员没有私有或保护属性的、没有引用类型的、没有非POD类类型的(即嵌套类都必须是POD)、没有指针到成员类型的(因为这个类型内含了this指针)。

2.c++中的POD

而在c++11中POD被释义为两个推广情况:平凡(trivial)和标准布局(standard-layout)

1.平凡(trivial):

      类型是平凡的(trivial),则可以静态初始化、可以用memcpy直接复制数据而不是必须用copy构造函数。其生存期始于它的对象的存储被定义,无须等到构造函数完成。平凡class或结构必须满足:

  • 有平凡的缺省构造函数,可用这样的默认语法:(SomeConstructor() = default;)
  • 有平凡的copy与move构造函数,可用默认语法.
  • 有平凡的copy与move运算符,可用默认语法.
  • 有平凡的destructor,不能是虚函数.

2. 标准布局(standard-layout)

      意味着它是有序的并且安排其成员兼容于C语言。这要求满足:

  • 没有虚函数
  • 没有虚基类
  • 所有非静态数据成员有相同的访问控制(public, private, protected)
  • 所有非静态数据成员,包括在任何基类中的,存在于类继承体系中的一个类中
  • 上述规则适用于所有基类与类继承体系中的所有非静态数据成员
  • 没有同一类型的基类型被定义为第一个非静态数据成员

 一个class/struct/union是POD,当它是平凡的、标准布局的,所有数据成员是POD.对象可以不满足其中一个但是满足另外一个。例如,类有复杂的move与copy构造函数,因此不是平凡的,但可能是标准布局因此能与C程序互操作。类似地,一个类的有public与private的非静态数据成员,因此不是标准布局,但可以是平凡的因此可以memcpy操作。

三、为什么C++中的对象有可能不是一个POD呢?

      c++中的特点之一就是--多态,多态的核心就是虚函数,有虚函数自然就有虚函数表(vtbl)和指向虚函数表的指针vptr,根据侯捷老师书中所述,在有虚函数和虚基类的继承链的情况下,编译器会优化扩充代码段。有了这点前提,我们继续看。我们定义两个类:ZooAnimal和Bear:

class ZooAnimal {
public:
    ZooAnimal();
    virtual ~ZooAnimal();

    virtual void animate();
    virtual void draw();
    //...
private:
    //ZooAnimal的animate()和draw()
    //所需要的数据
}

class Bear : public ZooAnimal {
    Bear();
    void animate();
    void draw();
    virtual void dance();
    //...

private:
    //Bear的animate()、draw()和dance()
    ...
    //所需要的数据
};

如果上述两个类的同类型对象之间赋值作为初值,则可以是安全的,可以实现逐位拷贝,如Bear  mm;  Bear nn = mm;

但是若 ZooAnimal  ll = mm;

这样的话,内部mm的vptr指向的是Bear的虚表,而ll中的vptr指向的应该是ZooAnimal中的虚表,如果此时可以实现逐位拷贝的话,指针之间的覆盖,直接将导致多态出现问题,所以逐位拷贝在c++中,并不是所有的对象都适用的,视情况稳定。

该处使用的url网络请求的数据。


总结

可知,逐位拷贝在C语言中是美好的,但是c++中不是所有的对象都适用,要根据对象的具体情况而定,充分考虑vptr的初值设定等问题,更要判断对象是否为POD对象,以及编译器的扩张优化等。

参考:《深入探索c++对象模型》--侯捷

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值