《More Effictive C++》学习笔记 — 基础议题 操作符 异常

条款3 — 绝对不要以多态方式处理数组

好吧,这个问题在《深度探索C++对象模型》也提到了。当时,我只在msvc上验证了下,发现并不是这样。现在又看到这个提议,我认真地研究了下。

1、C++标准中的规定

首先,我们来看看C++中是怎样规定的(摘自C++20草案):

In an array delete expression, if the dynamic type of the object to be deleted differs from its static type, the behavior is undefined

这和C++98中的规定保持一致,对于动态类型和静态类型不一致的对象(也就是我们尝试以多态方式处理的对象),我们尝试使用delete[] 的方式处理它们时,行为是未定义的。

2、编译器实现

msvcmingwgcc11.1.0上验证后,我发现并没有这个问题。它们都可以正确地释放派生类对象。

3、问题分析

这个问题说明C++标准对于 delete[] 中如何进行析构函数的绑定并不做限制。如果只调用了基类的析构函数,说明编译器肯定是通过静态调用析构函数实现的:

for (int i = 0; i < size; i++)
{
   
	arr[i].~CLS_Base();
}

现在,编译器都能正常处理该情况,说明它们都意识到通过动态类型调用是更好的选择。这也正是基于C++对于RTTI的支持,他们才能检测到数组真正的类型及应该调用的析构函数版本。目前,只有 delete[] 被用于非多态形式中的动静态类型不一致才会导致析构调用错误:

#include <iostream>
using namespace std;

class CLS_Base
{
   
public:
	~CLS_Base()
	{
   
		cout << "~CLS_Base()" << endl;
	}

	void test()
	{
   
		cout << "CLS_Base::test" << endl;
	}
};
class CLS_Derived : public CLS_Base
{
   
public:
	~CLS_Derived()
	{
   
		cout << "~CLS_Derived()" << endl;
	}

	void test()
	{
   
		cout << "CLS_Derived::test" << endl;
	}
};

void testArr(CLS_Base arr[], size_t size)
{
   
	for (int i = 0; i < size; i++)
	{
   
		arr[i].test();
	}
}

int main()
{
   
	CLS_Base* pBaseArr = new CLS_Derived[10];
	testArr(pBaseArr, 10);
	delete[] pBaseArr;
}

在这里插入图片描述
我本以为这种情况下,在test中打印i会出现神奇的数字,没想到结果是正确的。这说明即使对于非多态类型,现在编译器仍然会检测其数据类型,根据其真正的size决定 arr[i] 在实际内存中的偏移量。我认为这对编译器来说是一个合理的选择。

条款5 — 对定制的类型转换函数保持警觉

这里面需要我们关注的就是C++的转换准则之一:没有任何一个转换程序可以内含一个以上的用户定制转换行为。这也引出了我们如何不使用explicit关键字阻止隐式类型转换:

class CLS_Test
{
   
public:
	class CLS_Size
	{
   
	public:
		CLS_Size(int size) 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值