论坛首页 编程语言技术论坛

析构函数 管理指针成员

浏览 2894 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2008-02-23  
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;   
}

 

 

 

 

论坛首页 编程语言技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics