C++构造与析构

C++语言构造函数与析构函数需要注意的地方。

构造

考虑以下定义

struct Node
{
    char *name;
    int value;
    Node(char *name = "", int value = 0)
    {
        name = new char[strlen(name)+1];
        strcpy(name, name);
        value = value;
    }
}

声明两个对象

Node node1("child", 10), node2(node1);

这行语句创建了两个对象node1,node2,其中node2是用node1的成员进行初始化,现在改变node2成员值

strcpy(node2.name, "parent");
node2.value = 40;

打印对象的成员值如下

cout<<node1.name<<' '<<node1.value<<' '<<node2.name<<' '<<node2.value;

结果如下

parent 10 parent 40

问题出在Node结构成员name是一个指针类型,如果结构定义中没有复制构造函数,则编译器使用默认的构造函数,此构造函数在复制值类型与复制指针类型时实现方法不同,复制指针类型时仅仅复制指针的内容(所指向的地址),所以node1和node2的name指针指向了同一个地址。

解决这个问题的办法是自定义一个复制构造函数

struct Node
{
    char *name;
    int value;
    Node(char *name = "", int value = 0)
    {
        name = new char[strlen(name)+1];
        strcpy(name, name);
        value = value;
    }
    Node(const Node& node)
    {
        name = new char[strlen(node.name) + 1];
        strcpy(name, node.name);
        value = node.value;
}            

当然,还有一个类似的问题就是

node2 = node1;

这句代码也是对成员进行浅表复制,解决的办法就是自定义赋值构造函数,仅给出代码片段

Node& operator=(const Node& node)
{
    if(this != &n)    {    // no assignment to itself
        if(name != 0)
            delete [] name;  // 注意这里是 delete [],delete只是析构单个对象,而非字符数组
        name = new char[strlen(node.name) + 1];
        strcpy(name, node.name);
        value = node.value;
    }
    return *this;
}

析构

对于以上类型的对象,因为是值类型,所以如果是作为局部变量,当对象处于作用范围之外时将被销毁,被对象占用的内存也会得到释放。然而,这个对象占用的内存虽然被释放,但是跟这个对象相关联的内存则不一定被释放。如上面这个Node类型,有一个指向string的指针成员,因此,销毁Node类型对象时,对象的指针成员(name)所占用的内存被释放(32位机器上指针占用4byte),但是指针指向的string所占用的内存将会变得无法访问,这个内存也就无法被释放了。为了避免这个问题,类(结构)定义中需要包含析构函数。析构函数在对象被销毁时自动被调用,或者主动使用delete关键字调用析构函数。析构函数不接受参数,也不返回值。

在Node的定义增加一个析构函数

~Node()
{
    if(name != 0)
        delete [] name;
}

以上讨论了结构(struct)的构造函数和析构函数,对于类(class)的情况类似。

原文地址:https://www.cnblogs.com/sjjsxl/p/5021390.html