为什么类的析构函数"inlined"在仅包含类的头文件的 cpp 中
why the destructor of a class is "inlined" in a cpp which which ONLY includes the class's header file
通过转储生成的目标代码(TestCompiler. exe)。.o和TestA.o),我发现TriShape的析构函数的代码是在上面的.o文件中生成的。
即使TestCompiler.cpp没有尝试使用类TriShape的对象,为什么析构函数在.o文件中被"内联"?这样做对编译器有什么好处?
顺便说一句,我测试过的编译器是gcc 4.4.7 (linux), clang-600.0.54 (OSX)和VS2013。前两者显示了我上面提到的相同的结果。感谢您提前提出的建议和意见!
下面是我的程序:
//================================================================//
TestCompiler.cpp -碰巧包含TriShape.h,但甚至没有使用它
//#include "stdafx.h"
#include <stdio.h>
#include "TestA.h"
#define BUILD_DEBUG_CLASS_MEMBER // :)
#include "TriShape.h" // include it just for testing compiler/linker in our case
int main( int argc, char* argv[] )
{
printf( "TC: main start n" );
//TestA::gTestAFunc();
gTestAFunc();
// calls to TriShape::testVFunc, etc
//...
printf( "TC: main finish n" );
return 0;
}
//================================================================//
TestA.h
#pragma once
extern void gTestAFunc();
//================================================================//
TestA.cpp
#include <stdio.h>
#include "ClassA.h"
void gTestAFunc()
{
ClassA* pA = new ClassA();
pA->createS();
pA->removeS();
delete pA;
}
//================================================================//
ClassA.h
#pragma once
#include "Shape.h"
class ClassA
{
public:
ClassA()
: m_pShape( NULL )
{
}
void createS();
void removeS();
Shape* m_pShape;
};
//================================================================//
ClassA.cpp -包含TriShape.h
#include <stdio.h>
#include "ClassA.h"
//#define BUILD_DEBUG_CLASS_MEMBER // don't define it :)
#include "TriShape.h"
void ClassA::createS()
{
m_pShape = new TriShape;
}
void ClassA::removeS()
{
delete m_pShape;
m_pShape = NULL;
}
//================================================================//
Shape.h
#pragma once
class Shape //:: MemoryObject
{
public:
Shape()
: m_ptr( NULL )
{
}
virtual ~Shape()
{
}
inline virtual int testVFunc()
{
return -1;
}
Shape* m_ptr;
};
//================================================================//
trisshape .h -析构函数声明自己为内联
#pragma once
#include <assert.h>
#include "Shape.h"
#define FIX_NUM 0xABCD
class MyList
{
public:
MyList()
: m_dummy( FIX_NUM )
{
}
//TODO: inline it! :P
virtual ~MyList()
{
printf( "List dtor: this:%p size:%d dummy:0x%x n", this, sizeof( *this ), m_dummy );
assert( m_dummy == FIX_NUM );
//#pragma message( "List dtor here" )
}
int m_dummy;
};
class TriShape : public Shape
{
public:
TriShape()
//: m_debugMember()
{
printf( "TriShape ctor: this:%p size:%d n", this, sizeof( *this ) );
}
#if 1
//caseT1
virtual ~TriShape();
#else
//caseT2
virtual ~TriShape()
{
printf( "TriShape dtor IN class: this:%p size:%d n", this, sizeof( *this ) );
#pragma message( "TriShape dtor here IN class" )
}
#endif
virtual int testVFunc();
#ifdef BUILD_DEBUG_CLASS_MEMBER
MyList m_debugMember;
#endif
};
// inline dtor
#if 1
inline TriShape::~TriShape()
{
printf( "TriShape dtor AFTER class: this:%p size:%d n", this, sizeof( *this ) );
#pragma message( "TriShape dtor here AFTER class" )
#ifdef BUILD_DEBUG_CLASS_MEMBER
#pragma message("tit is defined: BUILD_DEBUG_CLASS_MEMBER")
#endif
}
#endif
// inline virutal func
inline int TriShape::testVFunc()
{
printf( "TriShape testVFunc AFTER class: this:%p size:%d n", this, sizeof( *this ) );
#pragma message( "TriShape testVFunc here AFTER class" )
#ifdef BUILD_DEBUG_CLASS_MEMBER
#pragma message("tit is defined: BUILD_DEBUG_CLASS_MEMBER")
#endif
return 0;
}
你描述了正确的症状,但给出了错误的诊断:析构函数没有内联。
编译器会发生什么?它编译包含TriShape.h
的TestCompiler.cpp
。预处理后,TriShape::~TriShape
的定义存在,编译器为其生成代码。
如果您不希望这些代码在不同的模块中被复制,请将其放在单独的cpp文件中,并将其与其他编译单元链接。
c++逻辑上一次编译一个文件。当编译testCompiler.cpp
时,它无法知道其他文件是否也包含析构函数的定义。因此,编译器必须悲观地编译它。只有链接器发现存在多个(不冲突的、合法的)定义。
根本原因是c++遵循C的编译模型。在一个更简洁的模型中,第一阶段解析器将找到所有的函数,然后链接器将确定它需要什么,然后第三阶段编译器将根据需要编译函数。这就是现代语言的运作方式。它也更快,因为阶段可以在时间上重叠,并且可以更好地并行化。
相关文章:
- .cpp和.h文件中的模板专用化声明
- 为什么两个不同的未命名名称空间可以共存于一个cpp文件中
- 命名空间中具有.h和.cpp文件的类
- 为什么我的主文件.cpp不打印头文件中的任何内容
- 生成文件错误 - 找不到文件 - *.cpp
- 如何在文件.cpp gtkmm中声明小部件
- 没有实现文件(.cpp)的派生类
- 如何使用"CMakeLists.txt"中的add_library将整个文件(.cpp,.h等)包含在目录中
- 如何在Linux / Windows操作系统上使用文件*.cpp一步编译下面的代码
- 关于 Linux .so 文件无法链接到主文件.cpp文件
- 文件.cpp从Windows到Linux
- Ubuntu C++ 编译器错误: g++: 错误: 文件.cpp: 没有这样的文件或目录
- 如何将文件.cpp编译为本机编译
- 使用模板类时,似乎无法包含除 main 以外的任何 cpp 文件.cpp
- 无法编译C++文件.cpp。C++98模式
- 为什么C++头文件不需要包含实现文件 (.cpp)
- 如何访问位于独立文件(.cpp)中的非成员函数
- 如何在Visual Studio Code中通过键盘快捷键切换头文件/cpp文件
- 如何将数据从stringstream写入文件(CPP)
- 为什么filestream不把空白写入文件cpp ?