C++ 前置声明错误使用导致的内存泄漏及正确使用方式

文章讲述了C++中前置声明的使用注意事项,包括如何导致内存泄漏,以及如何避免在互相引用的类中正确使用前置声明。作者强调了编译器的编译顺序对前置声明行为的影响,以及类成员的正确声明方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前置声明使用注意:

  1. 只能定义指向前置声明的类的指针或引用。
  2. 以前置声明类型为函数的参数或返回值,该函数只能声明不能定义。

1. 前置声明误用导致内存泄漏

看下面的代码:

#include <stdio.h>
class A;
void del(A*a){
	delete a;
}

class A{
public:
	A(){
		printf("abc/r/n");
	}
	~A(){
		printf("~abc/r/n");
	}
};

int main()
{
	A* a= new A;
	del(A);
}

编译和运行都不报错。

运行结果:

A()

但是并没有调用A的析构函数,为什么?违反了第二点以前置声明类型为函数的参数或返回值,该函数只能声明不能定义

编译时有警告:

<source>: In function ‘void del(A*)’:

<source>:4:9: warning: possible problem detected in invocation of ‘operator delete’ [-Wdelete-incomplete]

    4 | delete a;

        | ^~~~~~~~

<source>:3:13: warning: ‘a’ has incomplete type

    3 | void del(A* a){

        |             ~~~^

提示’a’是一个不完整类型。如果不认真看警告,真不容易发现。程序不会有错误,但是会有内存泄漏。

为什么会这样?
因为 C++ 编译器自上而下编译源文件,del(A* a)中a是指针,已经知道占据内存的大小,所以可以编译成功。
若在del中sizeof(A)获取A的大小则会提示“A是不完整类型”的错误而编译失败:

void del(A* a){
    printf("a size %d\r\n",sizeof(A));
	delete a;
}

若改成以下这样,是否可以:

#include <stdio.h>
class A;
void del(A*a);

class A{
public:
	A(){
		printf("abc/r/n");
	}
	~A(){
		printf("~abc/r/n");
	}
};

void del(A*a){
	delete a;
}

int main()
{
	A* a= new A;
	del(A);
}

当然是没问题的。

2. 前置声明常见使用方法

若两个类互相引用,则需要前置声明。
下面的代码是否有问题?

class A;

class B{
public:
    A a;
};

class A{
public:
    B b;
};

毫无疑问是有问题的,A和B初始化时递归初始化成员,进入死循环。再一个,class B中A a是不完整类型,违反了第一点只能定义指向前置声明的类的指针或引用。不能直接定义类成员,而应该定义成指针:

class A;

class B{
public:
    A* a;
};

class A{
public:
    B* b;
};

这样就没问题了,虽然class B中定义了A *a,A是不完整类型,但是指针的大小是确定的,并不影响B的定义。

思考一下,class A改成下面这样可以吗?

class A{
public:
    B b;
};

当然是可以的,因为B在A前已经完整定义了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值