zoukankan      html  css  js  c++  java
  • c++ 入门之深入探讨拷贝函数和内存分配

    在c++入门之深入探讨类的一些行为时,说明了拷贝函数即复制构造函数运用于如下场景:

    • 对象作为函数的参数,以值传递的方式传给函数。 
    • 对象作为函数的返回值,以值的方式从函数返回
    • 使用一个对象给另一个对象初始化

    针对上述的三种情况,实际上很多时候,我们都会用到;如果我们采用系统默认的拷贝函数,程序容易发生我们无法掌控的错误。通常情况,我们会注意到:我们在定义一个拷贝函数的时候,往往会这么定义:classname(const  classname& A),为什么一定要用引用类型传递参数呢?如果我们不采用引用类型,采用值传递:就陷入了问题的本身:我们试图定义自己的拷贝函数来解决值传递的过程中,调用拷贝函数的问题。假如我们的拷贝函数变量是值传递,那么当调用这个拷贝函数的时候,由于拷贝函数本身就是值传递,便使得再次调用拷贝函数,而一旦进行调用,又遇到值传递.....于是,陷入了死循环的过程。所以:拷贝函数一定要采用引用传递参数。

    关于newdelete:用new生成的空间在堆区,而不是栈区。

    我们关注一下这个事实:

     1 class StringBad
     2 {
     3 private:
     4     char *str;
     5     int len;
     6     static int num_strings; //= 0;//可见除了const 量之外,类内部成员是不能在内部赋初值的
     7 public:
     8     StringBad(const char * s);
     9     StringBad();
    10     ~StringBad();
    11 
    12     friend std::ostream & operator<<(std::ostream & os, const StringBad & st);
    13 };

    上面定义了一个类:关于这个类不再赘述类的一般特性。在此,我们仅仅关注这个点:char *str;即这个字符指针成员。如果我们定义了一个对象A,A.str = "hello world!".A.len = 10。假如,我们再定义一个对象B,B = A,那么,B.str = "hello world!",B.len = 10,这个也没什么问题。但问题在于:B.len 和A.len 变量的地址是不同的。B.str和A.str这两个指针自己的地址自然也是不同的,但他们却指向了同一个“"hello world!",也就是说,在定义B=A时,并没有将"hello world!"复制一遍,复制到另外一个内存空间,然后让B.str指向了这里。而是让B.str也指向了这个 "hello world!".即使得这个 "hello world!"看起来像一个公共资源!这实际上是十分危险的!!!假如我们变量B过期了,要被销毁,其指针变量指向的"hello world!"所在的内存被delete所回收,那么其实A.str这个时候指向的内存并不是“hello world”,而我们的本意是,让这些对象彼此独立,互不干扰,除非我们想这样(比如静态成员的存在)。

    实际上,上述问题反映了一个重要的问题:深拷贝和浅拷贝。如果我们只是复制了地址,而没有赋值地址的内容,则是浅拷贝,否则为深拷贝。

    总结:当我们在类中遇到指针成员时,务必要使得我们的拷贝函数成为深拷贝,而不是浅拷贝!!!(具体做法参考收藏的他人博文)

    我们应该了解new ,delete 运作的本质:

    1 char * p;
    2 p = new char[10];

    上述描述了 p 首先是一个指针,然后通过new 开辟了10个char型空间,我们让p指向这个10个char型空间。

    当对象被销毁时,会调用析构函数。析构函数中,应该包含:

    1 delete[] p;

    这表明了当这个对象被销毁后,与之关联的内存空间应该被销毁。delete[] p是什么含义呢?

    delete并不是说我们销毁了p 这个变量,而是销毁了p指向的内存区。实际上P并不需要我们去销毁,因为p本身在栈区,而栈区的内存机制,我们是很清楚的。

    我们再次强调:之所以我们要用delete来管理内存,是因为new分配的空间在堆区,堆区并不会随着对象的销毁而自行销毁,需要人为的对其销毁,new -delete就是“创建堆区空间”——“销毁堆区的机制”。但是作用域内的普通变量就不一样:他们生存在栈区,栈区的变量会随着作用域的变化,完成出栈,从而释放内存!

  • 相关阅读:
    线性代数之行列式的C#研究实现
    政府部门域名系统杂谈
    C#实现在foreach中删除集合中的元素
    RestServer 2.0 正式版发布
    常见的几种开源协议
    PostgreSQL学习手册(常用数据类型)
    一个很简单的淘宝优惠券搜索助手 大家看看有没有用吧
    做了一个淘宝内部优惠券分享平台支持微信公众号以及网站
    二十三种设计模式之原型模式的C#实现
    arcgis,mapinfo(mapxtreme),openlayers专业GIS系统开发
  • 原文地址:https://www.cnblogs.com/shaonianpi/p/9974251.html
Copyright © 2011-2022 走看看