浅谈C++的浅拷贝出现的错误

之前看一些资料提到浅拷贝的问题,即在复制对象时,只是对对象中的数据成员进行简单的赋值,默认拷贝构造函数执行的也是浅拷贝。如果对象中存在动态成员,如指针,那么仅仅做浅拷贝是不够的,并且容易引发错误,最经典的例子:

#include <iostream>
#include <stdio.h> 

using namespace std;

class A{
  public:
    A(){m_p = new int(10);};
    ~A(){cout << "destruction function" << endl;delete m_p;};
    int* m_p;
};

void copyTest(A atmp){
  ;
}

int main(){
  A a;
  copyTest(a);
}

执行这段代码会出现崩溃,因为析构函数里的delete m_p执行了两次,而m_p指向的是同一块内存。因为在调用copyTest时传入了对象a,atmp利用a作为参数执行了默认拷贝构造函数,但是只是简单地把对象a的m_p的内存地址拷贝给atmp的m_p,因此这个时候atmp.m_p只是指向了和a.m_p相同的内存块。

当copyTest执行完毕后,临时变量atmp会被销毁,这个时候析构函数被调用,delete了m_p指向的内存。而当main函数执行完毕后,a对象也需要被销毁,这个时候析构函数再次被执行,而这个时候m_p已经不知道指向什么地方了,delete操作引发程序崩溃。

解决这个问题的方法有很多:一种方法是实现智能指针,对m_p进行引用计数,当引用值为0时才执行delete;也可以每次把m_p的初始值设为NULL,每次执行delete操作前先检查m_p是否为NULL,delete后再让m_p指向NULL,这个方法其实道理和智能指针差不多,只是智能指针更合理有效地利用类进行管理;还有一种做法是重写拷贝构造函数,确保在对象复制时进行深拷贝,即重新分配内存空间,并且把a中m_p指向内存的内容拷贝到分配的空间。

以上这种情况只有在利用“值传递”复制对象时才发生,如果我们传递的是指针,就不会有这种情况了:

#include <iostream>
#include <stdio.h> 

using namespace std;

class A{
  public:
    A(){m_p = new int(10);};
    ~A(){cout << "destruction function" << endl;delete m_p;};
    int* m_p;
};

void copyTest(A* atmp){
  ;
}

int main(){
  A* a;
  copyTest(a);
}

因为传递到copyTest的参数只是一个地址,指向的还是对象a,并没有发生对象的复制,当然就不存在上面的深浅拷贝问题了。

以上就是小编为大家带来的浅谈C++的浅拷贝出现的错误全部内容了,希望大家多多支持我们~

(0)

相关推荐

  • 深入C++拷贝构造函数的总结详解

    拷贝构造函数是C++最基础的概念之一,大家自认为对拷贝构造函数了解么?请大家先回答一下三个问题:1. 以下函数哪个是拷贝构造函数,为什么?X::X(const X&);   X::X(X);   X::X(X&, int a=1);   X::X(X&, int a=1, b=2);  2. 一个类中可以存在多于一个的拷贝构造函数吗?3. 写出以下程序段的输出结果, 并说明为什么? 如果你都能回答无误的话,那么你已经对拷贝构造函数有了相当的了解. #include <iost

  • 深入C++中构造函数、拷贝构造函数、赋值操作符、析构函数的调用过程总结

    1 . 用同一个类的源对象构造一个目标对象时,会调用拷贝构造函数来构造目标对象,如果没有定义拷贝构造函数,将调用类的默认拷贝函数来构造目标对象.2 . 当一个函数的返回值为一个类的对象时,如果在调用函数中,没有定义一个对象来接收这个返回对象值,会用返回一个临时对象保存返回对象的值.在被调用函数结束时,这个临时对象被销毁.而当调用函数中有一个接受对象时,就将返回对象赋值给接收对象,这个返回对象在调用函数结束时调用析构函数.3. 当类有一个带有一个参数的构造函数时,可以用这个参数同类型的数据初始化这

  • C++拷贝构造函数(深拷贝与浅拷贝)详解

    对于普通类型的对象来说,它们之间的复制是很简单的,例如:int a=88;int b=a; 而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各种成员变量.下面看一个类对象拷贝的简单例子. 复制代码 代码如下: #include <iostream>using namespace std; class CExample {private:    int a;public:    CExample(int b)    { a=b;}    void Show ()    {       

  • C++浅拷贝与深拷贝及引用计数分析

    C++浅拷贝与深拷贝及引用计数分析 在C++开发中,经常遇到的一个问题就是与指针相关的内存管理问题,稍有不慎,就会造成内存泄露.内存破坏等严重的问题.不像Java一样,没有指针这个概念,所以也就不必担心与指针相关的一系列问题,但C++不同,从C语言沿袭下来的指针是其一大特点,我们常常要使用new/delete来动态管理内存,那么问题来了,特别是伴随着C++的继承机制,如野指针.无效指针使用.内存泄露.double free.堆碎片等等,这些问题就像地雷一样,一不小心就会踩那么几颗. 先来谈一下C

  • 深入理解C/C++中的写时拷贝

    写时拷贝 何为写时拷贝? 前面我说过深拷贝浅拷贝,今天我们来探究一下写时拷贝.深拷贝是补充了浅拷贝的不足,写时拷贝其实也就是补充一点深拷贝的不足.其实写时拷贝的意思就是: 当你读取到这个空间的时候,并不会开辟出一个一模一样的空间出来给你,当你真正需要拷贝的时候,那么他就会开辟出空间给你.也就是拖延版的深拷贝. 写时拷贝技术是通过"引用计数"实现的,在分配空间的时候多分配4个字节,用来记录有多少个指针指向块空间,当有新的指针指向这块空间时,引用计数加一,当要释放这块空间时,引用计数减一(

  • c++中深浅拷贝以及写时拷贝的实现示例代码

    本文主要给大家介绍了关于c++中深浅拷贝及写时拷贝实现的相关内容,分享出来供大家参考学习,下面话不多说,来一起看看详细的介绍: 一:浅拷贝&深拷贝 浅拷贝:在拷贝构造的时候,直接将原内容的地址交给要拷贝的类,两个类共同指向一片空间.但是存在很大的缺陷:①一旦对s2进行操作,s1的内容也会改变:②析构时先析构s2,再析构s1,但是由于s1,s2指向同一片空间,会导致一片空间的二次析构导致出错. 深拷贝:通过开辟和源空间大小相同的空间并将内容拷贝下来再进行操作.不论是否对s2进行操作,都会拷贝一片相

  • 浅谈C++的浅拷贝出现的错误

    之前看一些资料提到浅拷贝的问题,即在复制对象时,只是对对象中的数据成员进行简单的赋值,默认拷贝构造函数执行的也是浅拷贝.如果对象中存在动态成员,如指针,那么仅仅做浅拷贝是不够的,并且容易引发错误,最经典的例子: #include <iostream> #include <stdio.h> using namespace std; class A{ public: A(){m_p = new int(10);}; ~A(){cout << "destructio

  • 浅谈ASP.NETCore统一处理404错误都有哪些方式

    目录 方式一 方式二 自定义通配路由 方式三 方式四 方式五 web.config <customErrors> 节点中配置ASP.NET管道处理404错误 总结 当未找到网页并且应用程序返回 404 错误时,ASP.NET Core MVC 仅呈现通用浏览器错误页面,如下图所示 这不是很优雅,是吗?我们平时看到的404页面一般是这样的 还有这样的 试了下京东,地址不存在的时候是会重定向到首页 下面就来演示下ASP.NET Core中如何实现这种自定义的404页面处理. 新建项目 ASP.NE

  • 浅谈如何优雅处理JavaScript异步错误

    1. try/catch try/catch基本上是大家最常和async/await一起使用的,基本上我们会用它去包围大部分的异步方法.await关键字后面的promise一旦reject了,就会抛出一个异常错误. run(); async function run() { try { await Promise.ject(new Error('Oops!')); } catch (err) { console.error(error.message); } } try/catch同样也可以处理

  • 浅谈python连续赋值可能引发的错误

    今天写的代码片段: X = Y = [] .. X.append(x) Y.append(y) 其中x和y是读取的每一个数据的xy值,打算将其归入列表之后绘散点图,但是绘图出来却是一条直线,数据本身并不是这样分布的. 反复检查后,发现是X = Y =[]这一句的错误. 在python中,形如X = Y的拷贝都是浅拷贝,X和Y是公用同一块空间的,一旦对它们其中的任意一个进行数据操作,都会改变该空间的内容,除非重新赋一块空间,改变其指向的位置. 因此只需要改成: X = [] Y = [] 就可以运

  • 浅谈JavaScript中面向对象的的深拷贝和浅拷贝

    理解深拷贝和浅拷贝之前需要弄懂一些基础概念,内存中存储的变量类型分为值类型和引用类型. 1.值类型赋值的存储特点, 将变量内的数据全部拷贝一份, 存储给新的变量. 例如:var num = 123 :var num1=num; 表示变量中存储的数字是 123.然后将数据拷贝一份,就是将 123 拷贝一份. 那么内存中有 2 个 数组;将拷贝数据赋值给 num2,其特点是在内存中有两个数据副本.这可以理解为浅拷贝. 2.引用类型的赋值. var o={name:'张三'}: var obj=o;

  • 浅谈使用Python变量时要避免的3个错误

    Python编程中经常遇到一些莫名其妙的错误, 其实这不是语言本身的问题, 而是我们忽略了语言本身的一些特性导致的,今天就来看下使用Python变量时导致的3个不可思议的错误, 以后在编程中要多多注意. 关于Python编程运行时新手易犯错误,这里暂不作介绍,详情参见:Python运行的17个时新手常见错误小结 1. 可变数据类型作为函数定义中的默认参数 这似乎是对的?你写了一个小函数,比如,搜索当前页面上的链接,并可选将其附加到另一个提供的列表中. def search_for_links(p

  • 浅谈PHP中的错误处理和异常处理

    错误处理:          1. 语法错误     2. 运行时的错误     3. 逻辑错误 错误报告:                  错误E_ERROR         警告E_WARNING         注意E_NOTICE 开发阶段:开发时输出所有的错误报告,有利于我们进行调试 运行阶段:不要让程序输出任何一种错误报告 将错误报告写入日志中 一.   指定错误报告error_reporting=E_ALL(在php.inn) 二.   关闭错误输出display_errors=

  • 浅谈PHP错误类型及屏蔽方法

    程序只要在运行,就免不了会出现错误,错误很常见,比如Error,Notice,Warning等等.在PHP中,主要有以下3种错误类型. 1.注意(Notices) 这些都是比较小而且不严重的错误,比如去访问一个未被定义的变量.通常,这类的错误是不提示给用户的,但有时这些错误会影响到运行的结果. 2.警告(Warnings) 这就是稍微严重一些的错误了,比如想要包含include()一个本身不存在的文件.这样的错误信息会提示给用户,但不会导致程序终止运行. 3.致命错误(Fatal errors)

  • 浅谈Tensorflow由于版本问题出现的几种错误及解决方法

    1.AttributeError: 'module' object has no attribute 'rnn_cell' S:将tf.nn.rnn_cell替换为tf.contrib.rnn 2.TypeError: Expected int32, got list containing Tensors of type '_Message' instead. S:由于tf.concat的问题,将tf.concat(1, [conv1, conv2]) 的格式替换为tf.concat( [con

  • 浅谈Python程序的错误:变量未定义

    Python程序的错误种类 Python程序的错误分两种.一种是语法错误(syntax error).这种错误是语句的书写不符合Python语言的语法规定.第二种是逻辑错误(logic error).这种错误是指程序能运行,但功能不符合期望,比如"算错了"的情形. 变量未定义的错误 Python程序中,变量需要先定义后使用.如果没有这样做,就会出现变量未定义错误.这属于语法错误.Pycharm中,语法错误会用红色的波浪线标出来,如图1所示. 图1 Pycharm中,语法错误会用红色的波

随机推荐