`
clskkk2222
  • 浏览: 33791 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论
  • NeuronR: 引用因为用于向函数传递对象和从函数返回对象,该构造函数一般不应 ...
    复制构造函数

析构函数 管理指针成员

    博客分类:
  • C++
阅读更多

析构函数就是这样的一个特殊函数,它可以完成所需的资源回收,作为类构造函数的补充撤销类对象

时会自动调用析构函数

 

动态分配的对象只有在指向该对象的指针被删除时才撤销

 

当对象的引用或指针超出作用域时,不会运行析构函数,只有删除指向动态分配对象的指针或实际对

象(而不是对象的引用)超出作用域时,才会运行析构函数

 

撤销一个容器(不管是标准库容器还是内置数组)时,也会运行容器中的类类型元素的析构函数


容器中的元素总是按逆序撤销:首先撤销下标为 size() - 1 的元素,然后是下标为 size() - 2 的

元素……直到最后撤销下标为 [0] 的元素

 

析构函数通常用于释放在构造函数或在对象生命期内获取的资源


如果类需要析构函数,则它也需要赋值操作符和复制构造函数,这是一个有用的经验法则,这个规则

常称为三法则,指的是如果需要析构函数,则需要所有这三个复制控制成员

 

析构函数并不仅限于用来释放资源,一般而言,析构函数可以执行任意操作,该操作是类设计者希望

在该类对象的使用完毕之后执行的

 

与复制构造函数或赋值操作符不同,编译器总是会为我们合成一个析构函数

 

合成析构函数按对象创建时的逆序撤销每个非 static 成员,因此,它按成员在类中声明次序的逆序

撤销成员,对于类类型的每个成员,合成析构函数调用该成员的析构函数来撤销对象

 

撤销内置类型成员或复合类型的成员没什么影响,尤其是,合成析构函数并不删除指针成员所指向的

对象

 

析构函数是个成员函数,它的名字是在类名字之前加上一个代字号(~),它没有返回值,没有形参

,因为不能指定任何形参,所以不能重载析构函数,虽然可以为一个类定义多个构造函数,但只能提

供一个析构函数,应用于类的所有对象

 

析构函数与复制构造函数或赋值操作符之间的一个重要区别是,即使我们编写了自己的析构函数,合

成析构函数仍然运行

 

包含指针的类需要特别注意复制控制,原因是复制指针时只复制指针中的地址,而不会复制指针指向

的对象

 

大多数 C++ 类采用以下三种方法之一管理指针成员:
1. 指针成员采取常规指针型行为。这样的类具有指针的所有缺陷但无需特殊的复制控制
2. 类可以实现所谓的“智能指针”行为,指针所指向的对象是共享的,但类能够防止悬垂指针
3. 类采取值型行为,指针所指向的对象是唯一的,由每个类对象独立管理

 

具有指针成员且使用默认合成复制构造函数的类具有普通指针的所有缺陷,尤其是,类本身无法避免

悬垂指针

 

建议:管理指针成员
具有指针成员的对象一般需要定义复制控制成员,如果依赖合成版本,会给类的用户增加负担,用户

必须保证成员所指向的对象存在,只要还有对象指向该对象

 

为了管理具有指针成员的类,必须定义三个复制控制成员:复制构造函数、赋值操作符和析构函数。

这些成员可以定义指针成员的指针型行为或值型行为

 

#include <iostream>
#include <string>
#include <vector>
using namespace std;

class Apple{
    int i;    
public:
    Apple(int n):i(n){}
    ~Apple(){
        cout << "Aapple No." << i << " destructed" << endl;       
    }  
}; 


// class that has a pointer member that behaves like a plain pointer
class HasPtr {
public:
    // copy of the values we're given
    HasPtr(int *p, int i): ptr(p), val(i) { }
    
    // const members to return the value of the indicated data member
    int *get_ptr() const { return ptr; }
    int get_int() const { return val; }
    
    // non const members to change the indicated data member
    void set_ptr(int *p) { ptr = p; }
    void set_int(int i) { val = i; }
    
    // return or change the value pointed to, so ok for const objects
    int get_ptr_val() const { return *ptr; }
    void set_ptr_val(int val) const { *ptr = val; }

private:
    int *ptr;
    int val;
};


int main()
{
    Apple a(0);   // 
    
    {             // new scope
        Apple a1(1);
    }             //exit local scope; destructor called on a1
    
    Apple *a2 = 0;
    {
        a2 = new Apple(2);
    }             //thouth exit local scope ,destructor not called 
    cout << "Apple a2 still exist " << endl;
    delete a2;    //ok  destructor called on a2
    
    cout << "===========================" << endl; 
    Apple a3(3);
    Apple a4(4);
    Apple a5(5);
    {
          Apple as[3] = {a3,a4,a5};  
    }             //destruct order: a5 a4 a3
    
    int obj = 0;
    HasPtr ptr1(&obj, 42); // int* member points to obj, val is 42
    HasPtr ptr2(ptr1);     // int* member points to obj, val is 42

    ptr1.set_int(0); // changes val member only in ptr1
    cout << ptr2.get_int() << endl;  // returns 42
    cout << ptr1.get_int() << endl;  // returns 0

    ptr1.set_ptr_val(42); // sets object to which both ptr1 and ptr2 point
    cout << ptr2.get_ptr_val() << endl;   // returns 42

    int *ip = new int(42); // dynamically allocated int initialized to 42
    HasPtr ptr(ip, 10);    // Has Ptr points to same object as ip does
    delete ip;             // object pointed to by ip is freed
    ptr.set_ptr_val(0);    // disaster: The object to which Has Ptr points was freed!
    cout << ptr.get_ptr_val() << endl;

    int i = 42;
    HasPtr p1(&i, 42);
    HasPtr p2 = p1;
    cout << p2.get_ptr_val() << endl;
    p1.set_ptr_val(0);
    cout << p2.get_ptr_val() << endl;
     
    return 0;   
}

 

 

 

 

0
0
分享到:
评论

相关推荐

    C++带有指针成员的类处理方式详解

    但是如果一个类带了指针成员,那么需要我们自己来写一个析构函数来管理内存。在&lt;&lt;c&gt;&gt; 中写到,如果一个类需要我们自己写析构函数,那么这个类,也会需要我们自己写拷贝构造函数和拷贝赋值函数。 析构函数: 我们...

    高级c语言程序编程思想

    第9章 类的构造函数、析构函数与赋值函数 69 9.1 构造函数与析构函数的起源 69 9.2 构造函数的初始化表 70 9.3 构造和析构的次序 72 9.4 示例:类String的构造函数与析构函数 72 9.5 不要轻视拷贝构造函数与赋值函数...

    最新C++全套视频教程及实战开发

    教程目录复制下面的链接打开后即可查看: ... 主要学习内容包含: 1、熟悉面向对象的语言概述 2、熟练掌握c++语言的基本知识和类与对象及其高级应用 ...12、虚函数、纯虚函数、抽象类、虚析构函数等

    高质量C++/C编程指南

    第9章 类的构造函数、析构函数与赋值函数 69 9.1 构造函数与析构函数的起源 69 9.2 构造函数的初始化表 70 9.3 构造和析构的次序 72 9.4 示例:类STRING的构造函数与析构函数 72 9.5 不要轻视拷贝构造函数与赋值函数...

    C++ 定义一个类,类的成员变量没有指针

    编程环境:win10,vs2017 #include   代码01 namespace ds01 {  //类定义  struct DsSize  {  //没有明确写出构造和析构,编译器会使用默认构造、拷贝赋值、析构。  };    //测试程序 ...

    抽象类与虚函数的应用

    将析构函数声明为虚函数。 (2)定义两个类Cat、Dog,都继承自Animal,并重载Identify函数,显示动物的种类及名字。 (3)定义一个Tiger类,继承自Cat,重载Identify函数,显示动物的种类和名字。 (4)定义一个...

    高质量C C编程指南

    第9章 类的构造函数、析构函数与赋值函数 9.1 构造函数与析构函数的起源 9.2 构造函数的初始化表 9.3 构造和析构的次序 9.4 示例:类STRING的构造函数与析构函数 9.5 不要轻视拷贝构造函数与赋值函数 9.6 示例:类...

    C++智能指针的原理和实现.pdf

    智能指针主要思想是RAII思想,"使⽤对象管理资源",在类 的构造函数中获取资源,在类的析构函数中释放资源。智能指针的⾏为类似常规指针,重要的区别是它负责⾃动释放所指向的对象。 RAII是Resource Acquisition Is ...

    高质量编程C++、C

    第9章 类的构造函数、析构函数与赋值函数 9.1 构造函数与析构函数的起源 9.2 构造函数的初始化表 9.3 构造和析构的次序 9.4 示例:类String的构造函数与析构函数 9.5 不要轻视拷贝构造函数与赋值函数 9.6 示例...

    高质量C++_C编程指南

    第9 章 类的构造函数、析构函数与赋值函数 9.1 构造函数与析构函数的起源 9.2 构造函数的初始化表 9.3 构造和析构的次序 9.4 示例:类STRING 的构造函数与析构函数 9.5 不要轻视拷贝构造函数与赋值函数 9.6 示例:类...

    新手必看编程法则C++

    第9章类的构造函数、析构函数与赋值函数 9.1 构造函数与析构函数的起源 9.2 构造函数的初始化表 9.3 构造和析构的次序 9.4 示例:类String的构造函数与析构函数 9.5 不要轻视拷贝构造函数与赋值函数 9.6 示例:类...

    高质量C++编程指南.PDF

    第9章 类的构造函数、析构函数与赋值函数 9.1 构造函数与析构函数的起源 9.2 构造函数的初始化表 9.3 构造和析构的次序 9.4 示例:类String的构造函数与析构函数 9.5 不要轻视拷贝构造函数与赋值函数 9.6 示例:类...

    高质量C、C++编程指南

    第9 章 类的构造函数、析构函数与赋值函数 9.1 构造函数与析构函数的起源 9.2 构造函数的初始化表 9.3 构造和析构的次序 9.4 示例:类STRING 的构造函数与析构函数 9.5 不要轻视拷贝构造函数与赋值函数 9.6 示例:类...

    小型公共交通管理系

    程序主要包含了类、指针、构造函数、析构函数、循环变量、分支结构、文件的建立以及读写等基本C++知识。通过这次程序设计不但提高了我们处理问题的能力,而且更深一步对C++语言的某些函数的正确的使用。

    C++ 课程作业 第六章 数组指针与字符串2——vector类(图书管理)

    3、设计构造与析构函数,不要求输出信息,但各位同学可以自己输出并分析各个对象的创建与删除的情况: Book();//将m_ID初始化为0,表示这个一个未赋值对象 virtual ~Book();//无具体的工作 Book(const Book& other...

    高质量C++、C编程指南.doc )

    第9章 类的构造函数、析构函数与赋值函数 69 9.1 构造函数与析构函数的起源 69 9.2 构造函数的初始化表 70 9.3 构造和析构的次序 72 9.4 示例:类STRING的构造函数与析构函数 72 9.5 不要轻视拷贝构造函数与赋值函数...

    高质量C++C编程指南(非扫描高清版)(林锐博士)

    第9 章 类的构造函数、析构函数与赋值函数 9.1 构造函数与析构函数的起源. 9.2 构造函数的初始化表. 9.3 构造和析构的次序. 9.4 示例:类STRING 的构造函数与析构函数 9.5 不要轻视拷贝构造函数与赋值函数. ...

    Effective.C++.中文第二版.50条款doc文档.chm

    条款6:析构函数里对指针成员调用delete 条款7:预先准备好内存不够的情况 条款8: 写operator new和operator delete时要遵循常规 条款9: 避免隐藏标准形式的new 条款10: 如果写了operator new就要同时写operator ...

    高质量C/C++编程指南(PDF)

    第9 章 类的构造函数、析构函数与赋值函数 9.1 构造函数与析构函数的起源. 9.2 构造函数的初始化表. 9.3 构造和析构的次序. 9.4 示例:类STRING 的构造函数与析构函数 9.5 不要轻视拷贝构造函数与赋值函数. 9.6 示例...

    高质量C++编程指南

    第9章 类的构造函数、析构函数与赋值函数 69 9.1 构造函数与析构函数的起源 69 9.2 构造函数的初始化表 70 9.3 构造和析构的次序 72 9.4 示例:类String的构造函数与析构函数 72 9.5 不要轻视拷贝构造函数与赋值函数...

Global site tag (gtag.js) - Google Analytics