为什么类的析构函数"inlined"在仅包含类的头文件的 cpp 中

why the destructor of a class is "inlined" in a cpp which which ONLY includes the class's header file

本文关键字:文件 cpp 包含类 析构函数 inlined 为什么      更新时间:2023-10-16

通过转储生成的目标代码(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.hTestCompiler.cpp。预处理后,TriShape::~TriShape定义存在,编译器为其生成代码。

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

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

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