为什么一个类的析构函数是"内联"在一个cpp中,它只包含类的头文件

时间:2015-08-14 10:50:31

标签: c++ gcc

通过转储生成的目标代码(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;
}

2 个答案:

答案 0 :(得分:1)

您描述了正确的症状,但提供了错误的诊断:析构函数未内联。

编译器会发生什么?它会编译包含TestCompiler.cpp的{​​{1}}。在预处理之后,存在TriShape.h定义,因此编译器会为其生成代码。

如果您不希望在不同的模块中复制此代码,请将其放在自己的cpp文件中,并将其与其他编译单元链接。

答案 1 :(得分:1)

C ++在逻辑上一次编译一个文件。当它编译testCompiler.cpp时,它无法知道其他文件是否也包含析构函数的定义。因此,编译器必须是悲观的并且无论如何都要编译它。只有链接器发现存在多个(非冲突的,合法的)定义。

这是因为C ++遵循编译的C模型。在更清洁的模型中,第一阶段解析器将找到所有函数,然后链接器将确定它需要什么,然后第三阶段编译器将根据需要编译函数。这就是现代语言的工作方式。它也快得多,因为阶段可以在时间上重叠并更好地并行化。