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

前置声明使用注意:

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

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

看下面的代码:

#include 
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的析构函数,为什么?违反了第二点以前置声明类型为函数的参数或返回值,该函数只能声明不能定义

编译时有警告:

: In function ‘void del(A*)’:

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

    4 | delete a;

        | ^~~~~~~~

: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 
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前已经完整定义了。

你可能感兴趣的:(c++)