2015-06-23 20 views
0

這裏的棘手部分是TestCompiler.cpp中BUILD_DEBUG_CLASS_MEMBER 的定義,我知道我可以簡單地不定義它來解決bug (請參閱下面運行結果的說法)gcc內聯的行爲:內聯虛函數和尤其是析構函數在我的案例中

我的問題是:
爲什麼,在我的情況下,虛擬在線功能正在TestCompiler.obj內聯文件 即使我不叫刪除或TriShape/Shape的任何類方法。
2.爲什麼在運行時,TestCompiler.o的內聯版本被稱爲 ,但不是Class.o中的其他版本。 (不僅下面的rumtime結果,而且gdb顯示它。)

無論如何,這裏我只是想研究爲什麼gcc現在就這樣做。 例如,它使.obj非常大,但它可能有助於內聯儘可能多 想要...!?我只是猜測,我不完全明白。 (由於我的錯誤(我愚蠢的定義)是顯而易見的,所以我不想說這 是gcc的bug;))

BTW,我已經測試過的編譯器是gcc 4.4.7,也VS2013。 只有 前者引起斷言。 而且,原始代碼庫位於不是我的庫和 因此我不能輕易更改形狀文件。 (ClassA是一種工廠,Shape類是圖書館的核心。)

非常感謝您的耐心等待,我期待您的評論/回答。


我的程序(對不起,一點額外的測試代碼仍然...)。)

(ClassA的是一種工廠和形狀類是核心源自庫)

//================================================================// 
// TestCompiler.cpp 
// 

//#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 

#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 

#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) 
    { 
     printf("Shape ctor: this:%p size:%d \n", this, sizeof(*this)); 
    } 

    //TODO: inline it! :P 
    virtual ~Shape() 
    { 
     //m_ptr 
     printf("Shape dtor: this:%p size:%d \n", this, sizeof(*this)); 
    } 

    inline virtual int testVFunc() 
    { 
     return -1; 
    } 

    Shape* m_ptr; 
}; 


//test ONLY: 
//#include "TriShape.h" 

//================================================================// 
//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; 
} 

運行期間輸出

$ ./inlineTest 
TC: main start 
Shape ctor: this:0x995b018 size:8 
TriShape ctor: this:0x995b018 size:8 
TriShape dtor AFTER class: this:0x995b018 size:16 
List dtor: this:0x995b020 size:8 dummy:0x20fe1 
inlineTest: TriShape.h:22: virtual MyList::~MyList(): Assertion 
`m_dummy==0xABCD' failed. 
Aborted (core dumped) 

通過-S產生讀能夠對象代碼,以表明它是inli斯內德在這兩種.ASM

In TestCompiler.asm: 
The destructor is inlned up this section 
.section .text._ZN8TriShapeD1Ev,"axG",@progbits,_ZN8TriShapeD1Ev,comdat 
(...) 
call _ZN6MyListD1Ev 
(...) 
call _ZN5ShapeD2Ev 

In ClassA.asm: 
The destructor is inlned up this section 
.section .text._ZN8TriShapeD1Ev,"axG",@progbits,_ZN8TriShapeD1Ev,comdat 
(...) 
call _ZN5ShapeD2Ev 

通過鏈接器生成(約析構函數TriShape的grep的結果)

.text._ZN8TriShapeD1Ev 
0x0000000000000000 0x0 ClassA.o 
.text._ZN8TriShapeD0Ev 
0x0000000000000000 0x0 ClassA.o  //oops, ALL ZEROS means something?? 
(...) 
.rel.text._ZN8TriShapeD1Ev 
0x0000000000000000 0x0 /usr/lib/../lib/crt1.o 
.rel.text._ZN8TriShapeD0Ev 
0x0000000000000000 0x0 /usr/lib/../lib/crt1.o 
(...) 
.text._ZN8TriShapeD1Ev 
0x0000000008048a80 0xb9 TestCompiler.o 
0x0000000008048a80 _ZN8TriShapeD1Ev 
*fill* 0x0000000008048b39 0x1 90909090 
.text._ZN8TriShapeD0Ev 
0x0000000008048b3a 0xb9 TestCompiler.o 
0x0000000008048b3a _ZN8TriShapeD0Ev 
*fill* 0x0000000008048bf3 0x1 90909090 
+0

我不想讓我的帖子太長,所以目前我還沒有談到testVFunc()。請隨意跳過它。 –

+0

也許這有助於:http://stackoverflow.com/questions/733737/are-inline-virtual-functions-really-a-non-sense – Matt

+0

感謝您的迴應。其實我已經閱讀過這篇文章,並且找不到我想要的 - 爲什麼gcc在TestCompiler.obj中內聯,並且在鏈接/運行時選擇它。 此外,TestCompiler.cpp甚至不會調用TriShape/Shape的任何函數。 –

回答

1

不幸的是你違反了一個定義規則TriShape所以試圖猜測爲什麼映射文件編譯器做了一些特別的事情不太可能產生有用的信息。允許編譯器假定類和函數在所有源文件中都是相同的,所以它可以選擇一個並在所有地方執行該代碼。

+0

正如我在上面的報告中所陳述的那樣,我正在嘗試學習gcc的內部特性,但並不知道如何避免這裏的bug。爲什麼gcc會在每個包含TriShape的cpp中內聯析構函數?謝謝 –