浅拷贝、深拷贝 Bitwise Copy和Memberwise Copy

VisDrone2019数据集实战:从下载到YOLO格式转换的完整指南 本文提供了一份完整的VisDrone2019数据集实战指南,详细介绍了从数据集下载、理解其独特的标注格式,到转换为YOLO模型可直接训练格式的全过程。通过清晰的代码示例步骤讲解,帮助读者掌握处理复杂无人机视觉数据集的核心技能,为基于YOLO的目标检测模型训练做好准备。 阅读详情

转载:
http://blog.csdn.net/arcsinsin/article/details/9815937
这里写图片描述
C++中类的默认的拷贝构造函数是按位拷贝的,也就是直接将一个对象的成员值拷贝过来;
比如一个类A,我们不显示提供拷贝构造函数的话:
如下:

class{
 int a;
 char arr[10];
char *p;
};
A a1;
A a2=a1;

这个时候,a2和a1的成员 int a和arr[ ]是相同的值,成员是独立的,修改某一个的成员不会影响另外一个,但是这个时候要注意的是指针p;
虽然我们输出的结果一样,但是不能草率下决定。因为这个时候a2和a1的p值是一样的,也就是说两个指针指向同一个地方;
所以这样的拷贝会经常出现问题,比如两次释放指针的内存等。解决办法大家都知道是自己构造一个按内容拷贝的拷贝构造函数,这里我也就不多说了。
我想讨论的问题是如下的问题:
C++编译器在什么情况下不会按照默认的Bitwise copy来做呢?
首先有两种情况我不想说,1:就是含有的成员对象本身提供了拷贝构造函数(不管是默认的还是自己提供的),这个时候当拷贝这个对象的时候调用的是对象的类提供的拷贝构造函数。2:继承的基类有拷贝构造函数,这个时候编译器会插入基类的拷贝构造函数,而不是编译器自己来提供。这两种都不会按照默认的拷贝语意来做。
我想讨论下面两种:
3:含有虚函数的类;
考虑下面的代码:

class Foo
{
public:
 int a;
 Foo *next;
 virtual void Func(void){cout<<"call Foo::func()"<<endl;}
};
class D:public Foo
{
public:
 int c;
 virtual void Func(void){cout<<"call D::func()"<<endl;}
};
int main(void)
{
  D d;
 Foo f=d;
 d.Func();
 f.Func();
 system("pause");
 return 0;
}

输出的结果是什么呢?运行看看:结果完全按照我们想要的要求运行:call D::func() call Foo::func()
所以这个就是说,当含有虚函数的时候,我们的类会有虚函数表,每个对象会有vptr。如果我们的基类只是简单的将子类的vptr值拷贝过来,显然是不符合要求的,于是这个时候编译器会给我们自动的停用bitwise拷贝,而用reset将基类的vptr指向基类的虚函数表。所以这个时候是达到了我们的要求的。我想说的是,其他值会按照默认的按位拷贝,只是vptr不会,还有我们下一个将讨论的也不会。

4:虚继承
与第三种情况类似,但是有区别,这里有vbtl,然而vbtl是采用的重新初始化,而不是reset;
让我们看看例子:

class Raccoon : public virtual ZooAnimal
{
 public: Raccoon() { /* private data initialization */ }
Raccoon( int val ) { /* private data initialization */ }
// ... private: // all necessary data
 };
class RedPanda : public Raccoon
{
public: RedPanda() { /* private data initialization */ }
RedPanda( int val ) { /* private data initialization */ }
// ... private: // all necessary data
};

这里如果是两个一样的类的对象间进行拷贝,简单的按位拷贝就会解决问题,而我们的问题在于父类与子类之间的拷贝;
如:RedPanda little_red;
Raccoon little_critter = little_red;
这个时候,编译器会在默认的拷贝构造函数中插入初始化指向虚基类的指针,而不是reset。这个与类的内部存储结构有关,建议看看之后便一目了然了。


memberwise copy和bitwise copy
首先说一下深拷贝(memberwise copy)和浅拷贝(bitwise copy)的问题。一般来说,自己定义的copy ctor对于对象的拷贝会有严格的、符合语义的定义(人为错误、破坏因素除外)。然而,无论是自定义的还是默认的ctor,编译器都会插入对虚拟机制的处理代码,这就保证对象切片和拷贝正确的发生——可能会出乎你的意料,但符合C++的语法语义。

虚拟机制与拷贝方式
当类中没有虚拟机制、没有其他类对象的成员时(只包含built-in类型、指针或者数组),默认copy ctor进行的是bitwise copy,这会导致对象切片的发生。然而,当类中有虚拟机制,或者有其他类对象成员时,默认copy ctor采用的是memberwise copy,并且会对虚拟机制进行正确的拷贝。

因为包含虚拟机制的类在定义一个对象时,编译器会向ctor中添加初始化vtable和vbaseclasstable(依赖于具体编译器)的代码,这样可以保证vtable中的内容与类型完全匹配。也就是说MyBase和DerivedMyBase有这相似的VTABLE,但不是完全相同——例如DerivedMyBase中还可以定义自己的virtual函数,这样它的VTABLE就会有更多表项。

而多态的实现是通过将函数调用解析为VTABLE中的偏移量来实现。pMB->Get()可能会被编译器解析成:
(*pMB->__vtable[Offset_of_Get])();

而当MyBase作为虚基类时,访问其中的数据成员可能就是:
pMB->__vBaseClassMyBase->b;

那么,当“aMB = aDMB;”,copy ctor会执行memberwise copy,正确的初始化aMB的VTABLE,而不是仅仅将aDMB的VTABLE拷贝过来。如果是bitwise copy,aMB对象中的VTABLE将是aDMB的,aMB.Get()调用的将是DervieMyBase定义的Get(),这显然是不符合语义和逻辑的。

总而言之
对象切片和copy ctor是一个很复杂的东西,在有虚拟机制的情况下两者是紧密结合在一起的。因为对象切片和拷贝构造函数的问题,不通过指针或者引用无法达到多态的目的。

还有一个问题是赋值拷贝的问题,这个机制更复杂,因此Lippman建议不要再虚基类中使用数据成员。C#和java禁止了多重继承,并将interface作为一个单独的东西,消除了赋值拷贝带来的复杂性。关于赋值拷贝的问题,有机会再讨论。

DESeq2差异分析结果不会看?用这个R脚本5分钟生成发表级火山图热图 本文详细介绍了如何使用R语言快速可视化DESeq2差异分析结果,5分钟内生成可直接用于论文发表的火山图热图。通过解析DESeq2数据结构、展示ggplot2EnhancedVolcano包的绘图技巧,以及pheatmap包的热图定制方法,帮助研究者高效呈现差异表达基因分析结果。 阅读详情

相关推荐

深入浅出ASAP2标准:手把手教你编写解析A2L文件(含Python示例代码)

本文深入解析ASAP2标准下的A2L文件,涵盖基础概念、文件结构及Python实现代码,帮助开发者掌握汽车ECU标定测量中的关键数据管理技术。通过详细示例,展示如何编写解析A2L文件,提升电控数据管理效率。

happy2的博客 1069

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

深入C++ 之逐位拷贝(bitwise copy) 提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加 例如:第一章 Python 机器学习入门之pandas的使用 提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 系列文章目录 前言 一、pandas是什么? 二、使用步骤 1.引入库 2.读入数据 总结 前言 最近有重新翻阅的侯捷老师的《深度探索C++对象模型》一书,依然别有新意源源涌来,不禁感叹经典书籍的魅力,...

heary29的专栏 2260

【docker】--- 详解 WSL2 中的 Ubuntu Docker Desktop 的区别关系!

在编程的艺术世界里,代码灵感需要寻找到最佳的交融点,才能打造出令人为之惊叹的作品。而在这座秋知叶i博客的殿堂里,我们将共同追寻这种完美结合,为未来的世界留下属于我们的独特印记。

秋知叶i 1279

Memberwise copy(深拷贝)与Bitwise copy(浅拷贝)的区别

转自:http://blog.csdn.net/sghcpt/article/details/5578320 又加了一些自己补充。

KangRoger的专栏 3465

深入分析深拷贝(Memberwise Copy)浅拷贝(Bitwise Copy)

深拷贝浅拷贝基础:http://blog.csdn.net/songshimvp1/article/details/48244599 *********************************************************************************************************************************

松狮 2270

C++Bitwise Copy带来的问题实例讲解

在对象拷贝过程中,如果没有显示定义默认拷贝构造函数默认赋值构造函数,编译器会提供相应的缺省函数,该函数是"按位"进行拷贝或者赋值。对于只含有POD成员数据的简单类,bitwise copy方式绰绰有余。但是倘若类比较复杂,类成员中包含有指针、引用、虚函数时会出现错误。     以类A为例,类A定义如下图所示         假设创建对象a1,a2,a2通过a1拷贝,要是未定义默认拷贝构造...

神技圈子的博客 4726

Shallow Copy,Deep CopyBitwise CopyMemberwise Copy

在网上看到很多朋友对Shallow Copy,Deep CopyBitwise CopyMemberwise Copy这4者之间的关系的理解多有混淆,Stanley Lippman的“Inside the C++ Object Model”的讲解也比较晦涩难懂。玄机逸士在此给出一个简单的、明确的说明:)。请各位硕学高贤指正。 Java中的Clone也有浅克隆深克隆之分,分别对应C++

玄机逸士的专栏 2437

浅拷贝深拷贝以及Memberwise Copy Bitwise Copy

在网上看到很多朋友对Shallow Copy,Deep CopyBitwise CopyMemberwise Copy这4者之间的关系的理解多有混淆,Stanley Lippman的“Inside the C++ Object Model”的讲解也比较晦涩难懂,玄机逸士在此来一个简单的、明确的说明:)   Java中的Clone也有浅克隆深克隆之分,分别对应C++中的浅拷贝

ahuang1900的专栏 693

深拷贝浅拷贝memberwise copy bitwise copy

深拷贝:如果一个雷拥有资源,当这个类的对象发生复制过程时,k

yskyj的专栏 762

C++ Object Model:Default Memberwise Initialization/bitwise copy semantics及深拷贝/浅拷贝

Default Memberwise Initializationbitwise copy semantics的区别 当class object是以“相同class的另一个object“作为初值时,其内部是以所谓的default memberwise initialization手法完成的,也就是把每一个内建的或派生的data member的值,从某个object拷贝一份到

Invoker's Tower 1400

STL源码剖析——stl_algobase.h

STL标准中没有区分基本算法或复杂算法,单SGI把常用的一些算法定义在只中,其他算法定义在中。 stl_algobase.h中的算法,比较值得学习的是copy(),它“无所不用其极”的改善效率。copy的目的是复制一段元素到指定区间,复制操作最容易想到赋值操作符=,但是有的赋值操作符=是trivial的,可以直接拷贝。关于赋值操作符=是不是trivial的,可以参考“Member

Smile&搁浅 3750

深入探索C++对象模型--详解深拷贝浅拷贝以及拷贝构造的建构

深入探索C++对象模型--详解深拷贝浅拷贝以及拷贝构造的建构

chenglinhust的专栏 1384

第2章 构造函数语义学2 : Copy Constructor的构造操作

默认行为,递归调用成员拷贝构造函数或复制值。必须显式定义拷贝构造函数来管理深拷贝资源(如指针)。

qq_40178082的博客 844

构造函数语意学 笔记(二)

第二篇笔记拖了好长时间,因为我自身也是一知半解。所幸在查阅许多资料后,略有所得,故与诸君共享。这篇可能理解起来比较晦涩,我尽可能做好铺垫。 若存在错误 请指正 万分感想 铺垫:     1.      Default memberwise initialization and bitwise copy 概念的区分理解。说实话,一开始我也不明白,后来翻阅了下资料,知道涉及到深浅拷贝

莫利斯安的博客 827

[C++]bitwisememberwise的区别

在看《深入探索C++对象模型》这本书的时候,我看见了bitwise senimaticsmemberwise senimatics,看的时候还不清楚这两个是什么意思,书本上直接使用的是英文,所以我的直译就是位逐次语意成员逐次语意,经过一番百度后才发现原来就是简单的浅拷贝深拷贝的区别,既然自己已经百度了,不妨就顺便把这两者给做个简单的分析吧。进入正题: 在探索C++模型书上提到的,如果

李正浩的博客 4755

两个比较容易混淆的概念:Default Memberwise InitializationBitwise Copy

一、首先要分清楚这两者之间的关系:两个概念属于不同“集合”(但有部分交集)。 1. Default Memberwise Initialization是与user defined Initialization相对应的。是从编译器(计算机)与程序员(用户)的角度出发; 2. bitwise copy 是与memberwise copy相对应的。是两种不同的拷贝方式,编译器通常为了效率会选择bit

只要踏出一步,路就在前方——zssure 5935

C++中慎用逐位拷贝(bitwise copy)的函数

1.简单介绍C语言中的memcpy(),memset(),memcmp()函数   memcpy(),memset(),memcmp()等这些内存操作函数经常会帮我们完成一些数据复制、赋值等操作。因为C语言中,无论是内置类型,还是自定义类的结构类型(struct),其内存模型对于我们来说都是可知的,透明的。所以我们可以对该对象的底层字节序列一一进行操作,简单而有效。例如如下代码:struct ST

3018

Bitwise copy semantics

一下声明展现了Bitwise copy semantics 

陆业聪 1559

Maxwell参数化建模优化分析.pdf

Maxwell参数化建模优化分析.pdf

ROM修改自启脚本生成工具 自启脚本辅助工具

资源描述:自做工具 用于安卓设备修改自启脚本辅助工具按需生成rc与sh脚本自带多个基础模板实际操作需要根据安卓版本不同自行手动调整查看博文了解详细:https://blog.csdn.net/u011283906/article/details/160692009?spm=1001.2014.3001.5352

上一篇: C++ static关键字
下一篇: 防SQL注入
HelloWorld__LL
博客等级 码龄16年 2粉丝 16原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值