c++ - 在 h 文件上内联发布版本和在 cpp 上实现调试版本的函数
问题描述
我正在维护一个遗留的 MFC 应用程序,我看到的模式与Windows 下的面向对象编程中的模式完全一样,其中相关部分是:
Persview.h
#ifndef _DEBUG // debug version in persview.cpp
inline CPersDoc* CPersView::GetDocument()
{ return (CPersDoc*)m_pDocument; }
#endif
Persview.cpp
#ifdef _DEBUG
CPersDoc* CPersView::GetDocument() // non-debug version is inline
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CPersView)));
return (CPersView*)m_pDocument;
}
#endif //_DEBUG
如果我在互联网上搜索它,我会看到该模式被广泛应用,所以我认为它是向导生成的代码。
我的问题是:在 .h 文件中内联发布版本并在 .cpp 文件中进行调试是否有任何优势或其他充分理由?为什么不将两者放在同一个文件中呢?
解决方案
请注意,您引用的这本书是 1994 年出版的。当时的 C++ 非常不同,而微软的 C++ 编译器则不然。猜测一下,inline
当时有不同的语义,并指示编译器内联函数调用,即使在调试配置中也是如此。
除此之外,还有技术原因:编译器只能内联一个函数,如果它看到完整的定义。如果您希望它内联在不同的编译单元中,则函数定义需要在头文件中。另一方面,您不能将非内联函数放在标头中,因为如果标头包含在多个编译单元中,这将违反单一定义规则。在这种情况下,您会收到链接器错误。
如果您希望摆脱代码重复并仍然获得相同的好处,您可以: 只需将调试版本移动到标题中,标记它inline
,然后删除预处理器条件。在ASSERT
非调试配置中编译为空,编译器可以(可能会)内联函数调用。对于调试配置,编译器不会执行任何优化,并为函数调用发出代码。函数调用在调试配置中是可取的,因为它们会产生更有意义的堆栈跟踪。
推荐阅读
- oracle - 打破 oracle sqldeveloper 中的任何异常
- java - 如何在 DragEvent 期间将 Imageview On Runtime 定位在特定坐标处?
- jq - 使用 jq 循环对象并返回一个迭代值
- python - python类:逐步运行函数并保存
- android - 将家庭活动设置为默认值
- flutter - 是否需要在 Hive 中注册对象列表?
- pandas - 如何将熊猫系列转换为附图所示的数据框?
- amazon-web-services - AWS - 实例上的 SSM 代理:[<>] 不起作用
- java - 将 Instant 转换为 OffsetDateTime 然后在 OffsetDateTime 上的 Instant.parse() 在零秒情况下导致 DateTimeParseException
- jekyll - 让 livereload 在 Jekyll 4.2.0 和 Bundler 上工作