Reputation: 31
By dumping the object code generated (TestCompiler.o and TestA.o), I have found that the code of the destructor of TriShape is generated in BOTH the .o file above.
Even though TestCompiler.cpp DOES NOT try to use the object of the class TriShape, why the destructor is "inlined" in the .o file? What is the benefit for the compiler in doing so??
BTW, the compiler I have tested is gcc 4.4.7 (linux), clang-600.0.54 (OSX) and also VS2013. The former two shows the same result which I have mentioned above.
Thank you for your suggestions and advice in advance!
Here is my program:
//================================================================//
TestCompiler.cpp - which, by chance, includes TriShape.h but doesn't even use it
//#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 - which includes 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 - destructor declared itself to be inline
#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;
}
Upvotes: 0
Views: 83
Reputation: 179809
The C++ compiles one file at a time, logically. When it compiles testCompiler.cpp
, it has no way to know whether other files will also contain a definition of a destructor. Therefore, the compiler has to be pessimistic and compile it anyway. Only the linker discovers that there are multiple (non-conflicting, legal) definitions.
The root cause for this is that C++ follows the C model of compilation. In a cleaner model, the first stage parser would find all the functions, the linker would then determine what it needed, and then the third stage compiler would compile the functions as needed. This is how modern languages work. It's also a lot faster because the stages can overlap in time and parallelize better.
Upvotes: 1
Reputation: 148900
You describe the proper symptom, but give a wrong diagnostic: the destructor was not inlined.
What happens for the compiler? It compiles TestCompiler.cpp
that includes TriShape.h
. After the pre-processing, the definition of TriShape::~TriShape
is present, so the compiler generates code for it.
If you do not want this code to be duplicated in different modules, put it in its own cpp file and link it with the other compilation units.
Upvotes: 1