通过转储生成的目标代码(TestCompiler.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;
};
//================================================================//
TriShape.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;
}
答案 0 :(得分:1)
您描述了正确的症状,但提供了错误的诊断:析构函数未内联。
编译器会发生什么?它会编译包含TestCompiler.cpp
的{{1}}。在预处理之后,存在TriShape.h
的定义,因此编译器会为其生成代码。
如果您不希望在不同的模块中复制此代码,请将其放在自己的cpp文件中,并将其与其他编译单元链接。
答案 1 :(得分:1)
C ++在逻辑上一次编译一个文件。当它编译testCompiler.cpp
时,它无法知道其他文件是否也包含析构函数的定义。因此,编译器必须是悲观的并且无论如何都要编译它。只有链接器发现存在多个(非冲突的,合法的)定义。
这是因为C ++遵循编译的C模型。在更清洁的模型中,第一阶段解析器将找到所有函数,然后链接器将确定它需要什么,然后第三阶段编译器将根据需要编译函数。这就是现代语言的工作方式。它也快得多,因为阶段可以在时间上重叠并更好地并行化。