C++之类成员间指针处理

在一个类中,如果类没有指针成员,一切方便,因为默认合成的析构函数会自动处理所有的内存。但是如果一个类带了指针成员,那么需要我们自己来写一个析构函数来管理内存。

在<<c++ primer>> 中写到,如果一个类需要我们自己写析构函数,那么这个类,也会需要我们自己写拷贝构造函数和拷贝赋值函数。

下面我们先定义一个类头文件带指针:

HasPtr.h

#ifndef CLASSPOINTER_HASPTR_H
#define CLASSPOINTER_HASPTR_H


class HasPtr {
public:
    HasPtr(int i, int *p);   //构造函数

    ~HasPtr();  //析构函数

    int get_ptr_value();

    void set_ptr_value(int *p);

    int get_val();

    void set_val(int v);

private:
    int val;
    int *ptr;
};


#endif //CLASSPOINTER_HASPTR_H

HasPtr.cpp类的实现:

#include "HasPtr.h"
#include <iostream>

using namespace std;

HasPtr::HasPtr(int i, int *p) {
    val = i;
    ptr = p;
}

int HasPtr::get_ptr_value() {
    return *ptr;
}

void HasPtr::set_ptr_value(int *p) {
    ptr = p;
}

int HasPtr::get_val() {
    return val;
}

void HasPtr::set_val(int v) {
    val = v;
}

HasPtr::~HasPtr() {
    cout << "Destructor of HasPtr!" << endl;
}

main.cpp

#include <iostream>
#include "HasPtr.h"

using namespace std;

int main() {
    int temp = 100;
    HasPtr ptr(2, &temp);
    cout << ptr.get_ptr_value() << endl;
    cout << ptr.get_val() << endl;
    system("PAUSE");
    return 0;
}

结果:

100
2
请按任意键继续. . .

按下任意键:

100
2
请按任意键继续. . .

Destructor of HasPtr!

Process finished with exit code 0

执行主函数,我们发现在按下任意键时,析构函数自动调用了。

在main方法中,stack(栈)上定义好了一个类的实例化对象,当退出main函数之后,自动调用类的析构函数。

如果我们将对象的声明改为动态的,也即是放在heap(堆)上,会有什么特点,因此main函数我们将改为:

main.cpp

#include <iostream>
#include "HasPtr.h"

using namespace std;

int main() {
    int temp = 100;
    HasPtr *ptr = new HasPtr(2, &temp);
    cout << ptr->get_ptr_value() << endl;
    cout << ptr->get_val() << endl;
    system("PAUSE");
    return 0;
}

结果:

100
2
请按任意键继续. . .

按下任意键:

100
2
请按任意键继续. . .


Process finished with exit code 0

细心的同学已经发现,这时候的析构函数并没有执行。要怎么做它才会执行呢?我们可以尝试删除指针,在return前增加delete (ptr):

main.cpp

#include <iostream>
#include "HasPtr.h"

using namespace std;

int main() {
    int temp = 100;
    HasPtr *ptr = new HasPtr(2, &temp);
    cout << ptr->get_ptr_value() << endl;
    cout << ptr->get_val() << endl;
    system("PAUSE");
    delete(ptr);
    return 0;
}

结果:

100
2
请按任意键继续. . .

按下任意键:

100
2
请按任意键继续. . .

Destructor of HasPtr!

Process finished with exit code 0

这时我们发现析构函数执行了!

结论:

  1. 当一个对象在stack(栈)上时,析构函数自动调用。
  2. 方一个函数在heap(堆)上时,需要用delete语句,析构函数才会被执行。

下面我们演示在栈上删除指针会有什么发生(仅需修改部分代码即可):

HasPtr.cpp

#include "HasPtr.h"
#include <iostream>

using namespace std;

HasPtr::HasPtr(int i, int *p) {
    val = i;
    ptr = p;
}

int HasPtr::get_ptr_value() {
    return *ptr;
}

void HasPtr::set_ptr_value(int *p) {
    ptr = p;
}

int HasPtr::get_val() {
    return val;
}

void HasPtr::set_val(int v) {
    val = v;
}

HasPtr::~HasPtr() {
    cout << "Destructor of HasPtr!" << endl;
    delete(ptr); // 析构函数中删除指针
}

main.cpp

#include <iostream>
#include "HasPtr.h"

using namespace std;

int main() {
    int temp = 100;
    HasPtr ptr(2, &temp);
    cout << ptr.get_ptr_value() << endl;
    cout << ptr.get_val() << endl;
    system("PAUSE");
    return 0;
}

结果:

100
2
请按任意键继续. . .

Destructor of HasPtr!

Process finished with exit code 0

正常打印,那也没有问题啊。由于本人测试实在CLion里面执行的,编译器具有保护机制,故而没有出现错误。当尝试使用命令行执行后,正常打印,但是抛出了类似这样的错误。

由此看来delete不能删除stack上的指针。

下面我们使用动态参数来测试(仅需改变main.cpp):

main.cpp

#include <iostream>
#include "HasPtr.h"

using namespace std;

int main() {
    int *temp = new int(100);
    HasPtr ptr(2, temp);
    cout << ptr.get_ptr_value() << endl;
    cout << ptr.get_val() << endl;
    system("PAUSE");
    return 0;
}

结果:

100
2
请按任意键继续. . .

Destructor of HasPtr!

Process finished with exit code 0

无论在哪里执行,都不会抛出错误,因为指针的删除是在堆上操作的。

结论:

  1. delete语句不能够直接删除stack上的指针值。
  2. delete语句只能删除heap上的指针值,也就是new的对象。

默认拷贝函数和默认赋值操作:

这里我们调用默认的构造函数和默认的赋值操作,看看会出现什么,为了方便查看,我在析构函数中打印了当前对象的地址,以及在main方法中打印了对象地址,这样就可以看到哪个对象调用了析构函数:

HasPtr.cpp

#include "HasPtr.h"
#include <iostream>

using namespace std;

HasPtr::HasPtr(int i, int *p) {
    val = i;
    ptr = p;
}

int HasPtr::get_ptr_value() {
    return *ptr;
}

void HasPtr::set_ptr_value(int *p) {
    ptr = p;
}

int HasPtr::get_val() {
    return val;
}

void HasPtr::set_val(int v) {
    val = v;
}

HasPtr::~HasPtr() {
    cout << "Destructor of HasPtr!" << this << endl;
    delete(ptr);
}

main.cpp

#include <iostream>
#include "HasPtr.h"

using namespace std;

int main() {
    int *temp = new int(100);
    HasPtr ptr(2, temp);
    cout << "ptr------------------>" << &ptr << endl;
    cout << ptr.get_ptr_value() << endl;
    cout << ptr.get_val() << endl;

    HasPtr ptr2(ptr);
    cout << "ptr2----------------->" << &ptr << endl;
    cout << ptr2.get_ptr_value() << endl;
    cout << ptr2.get_val() << endl;

    HasPtr ptr3 = ptr;
    cout << "ptr3----------------->" << &ptr << endl;
    cout << ptr3.get_ptr_value() << endl;
    cout << ptr3.get_val() << endl;

    system("PAUSE");
    return 0;
}

结果:

ptr------------------>0x28ff24
100
2
ptr2----------------->0x28ff24
100
2
ptr3----------------->0x28ff24
100
2
请按任意键继续. . .

Destructor of HasPtr!0x28ff14
Destructor of HasPtr!0x28ff1c
Destructor of HasPtr!0x28ff24

Process finished with exit code 0

拷贝默认构造函数和赋值操作,将会直接复制指针值,不是指针所指向的值。是指针的变量,也是指针的地址。

调用delete指针值时,删除的值在不同调用时候不同,也就是说明指针值指向的内存地址在调用的时候是重新分配的。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值