C++自定义异常类存放位置及友元访问、全局变量相关问题
问题1回答
不合理,核心原因如下:
- 该全局实例对应的
Invalid_C_Exception类定义在Foo.cpp内部,属于当前编译单元的私有类型,其他编译单元完全看不到这个类的定义,既无法捕获该类型的异常,也无法主动抛出这个全局实例,对外完全不可用。 - 全局对象存在初始化顺序不确定的问题:
Invalid_C_Exc的初始化可能早于Foo::CHAR_SET的初始化,此时如果调用what()方法访问未初始化的CHAR_SET会触发未定义行为。 - 异常的常规使用方式是抛出临时对象,全局异常实例完全没有存在的必要,多线程场景下如果异常类存在可变状态还会引发线程安全问题。
问题2回答
核心原因是你声明的友元类和实际定义的异常类根本不是同一个类型:
你在Bar命名空间内的Foo类里声明的友元是Bar::Invalid_C_Exception,而你在Foo.cpp里定义的Invalid_C_Exception位于全局命名空间,两者属于完全无关的两个类,自然不享有Foo的友元访问权限。
另外即使你把异常类挪到Bar命名空间下修复了这个问题,也不推荐让异常类直接访问业务类的私有成员,更合理的方式是在Foo类里提供公有的静态接口返回允许的字符集合,降低两者的耦合度。
问题3回答
合理的存放方案
如果该异常确实只和Foo类强相关,推荐两种写法:
- 将
Invalid_C_Exception定义为Bar::Foo的公开内部类,声明放在Foo.h中,实现可以放在Foo.cpp中,对外可以通过Bar::Foo::Invalid_C_Exception引用。 - 将
Invalid_C_Exception和Foo放在同一个Bar命名空间下,声明放在Foo.h或者同命名空间下独立的异常头文件中,实现放在对应的源文件里。
你当前做法的问题
把异常类的声明和实现全放在Foo.cpp里的做法非常不合适:
- 其他调用
Foo接口的代码完全感知不到这个异常类的存在,只能捕获父类std::exception,无法做针对该异常的精确处理。 - 不符合C++常规编码规范,对外可见的类型定义应该放在头文件中,仅把非inline的实现放在源文件里。
内容的提问来源于stack exchange,提问作者digito_evo
相关产品推荐
相关产品推荐

