這裏的棘手部分是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
我不想讓我的帖子太長,所以目前我還沒有談到testVFunc()。請隨意跳過它。 –
也許這有助於:http://stackoverflow.com/questions/733737/are-inline-virtual-functions-really-a-non-sense – Matt
感謝您的迴應。其實我已經閱讀過這篇文章,並且找不到我想要的 - 爲什麼gcc在TestCompiler.obj中內聯,並且在鏈接/運行時選擇它。 此外,TestCompiler.cpp甚至不會調用TriShape/Shape的任何函數。 –