2010-01-24 41 views
8

有沒有什麼辦法可以查看默認函數(例如,默認拷貝構造函數,默認賦值運算符),如VC++ 2008編譯器爲沒有定義它們的類生成的?查看編譯器生成的默認函數?

+1

似乎有關於你的問題有些混亂。你是說如何查看函數原型,如何查看哪些是默認的以及我已經實現了哪些,或者如何查看默認實現的代碼? – 2010-01-24 23:45:10

回答

11

使用clang編譯器,您可以通過傳遞-ast-dump參數來查看它們。鏘仍處於發展階段,但你已經可以使用它的這些東西:

[[email protected] cpp]$ cat main1.cpp 
struct A { }; 
[[email protected] cpp]$ clang++ -cc1 -ast-dump main1.cpp 
typedef char *__builtin_va_list; 
struct A { 
public: 
    struct A; 
    inline A(); 
    inline A(struct A const &); 
    inline struct A &operator=(struct A const &); 
    inline void ~A(); 
}; 
[[email protected] cpp]$ 

我希望這是你問什麼。讓我們改變代碼並再次查看。

[[email protected] cpp]$ cat main1.cpp 
struct M { M(M&); }; 
struct A { M m; }; 
[[email protected] cpp]$ clang++ -cc1 -ast-dump main1.cpp 
typedef char *__builtin_va_list; 
struct M { 
public: 
    struct M; 
    M(struct M &); 
    inline struct M &operator=(struct M const &); 
    inline void ~M(); 
}; 
struct A { 
public: 
    struct A; 
    struct M m; 
    inline A(); 
    inline A(struct A &); 
    inline struct A &operator=(struct A const &); 
    inline void ~A(); 
}; 
[[email protected] cpp]$ 

通知A隱式聲明的拷貝構造函數怎麼現在有一個非const引用參數,因爲它的成員之一,有太多(成員m),以及M已宣佈沒有默認構造函數。

爲了獲取生成的代碼,可以讓它發出虛擬機中間語言。讓我們來看看在生成的代碼如下:

struct A { virtual void f(); int a; }; 
A f() { A a; a = A(); return a; } // using def-ctor, assignment and copy-ctor 

[[email protected] cpp]$ clang++ -cc1 -O1 -emit-llvm -o - main1.cpp | c++filt 
[ snippet ] 
define linkonce_odr void @A::A()(%struct.A* nocapture %this) nounwind align 2 { 
entry: 
    %0 = getelementptr inbounds %struct.A* %this, i32 0, i32 0 ; <i8***> [#uses=1] 
    store i8** getelementptr inbounds ([3 x i8*]* @vtable for A, i32 0, i32 2), i8*** %0 
    ret void 
} 

define linkonce_odr %struct.A* @A::operator=(A const&)(%struct.A* %this, 
    %struct.A* nocapture) nounwind align 2 { 
entry: 
    %tmp = getelementptr inbounds %struct.A* %this, i32 0, i32 1 ; <i32*> [#uses=1] 
    %tmp2 = getelementptr inbounds %struct.A* %0, i32 0, i32 1 ; <i32*> [#uses=1] 
    %tmp3 = load i32* %tmp2       ; <i32> [#uses=1] 
    store i32 %tmp3, i32* %tmp 
    ret %struct.A* %this 
} 

define linkonce_odr void @A::A(A const&)(%struct.A* nocapture %this, %struct.A* nocapture) 
    nounwind align 2 { 
entry: 
    %tmp = getelementptr inbounds %struct.A* %this, i32 0, i32 1 ; <i32*> [#uses=1] 
    %tmp2 = getelementptr inbounds %struct.A* %0, i32 0, i32 1 ; <i32*> [#uses=1] 
    %tmp3 = load i32* %tmp2       ; <i32> [#uses=1] 
    store i32 %tmp3, i32* %tmp 
    %1 = getelementptr inbounds %struct.A* %this, i32 0, i32 0 ; <i8***> [#uses=1] 
    store i8** getelementptr inbounds ([3 x i8*]* @vtable for A, i32 0, i32 2), i8*** %1 
    ret void 
} 

現在,我不明白,中間語言(這是在llvm.org定義)。但是您可以使用llvm編譯器將所有代碼翻譯爲C:

[[email protected] cpp]$ clang++ -cc1 -O1 -emit-llvm -o - main1.cpp | llc -march=c -o - | c++filt 
[snippet] 
void A::A()(struct l_struct.A *llvm_cbe_this) { 
    *((&llvm_cbe_this->field0)) = ((&_ZTV1A.array[((signed int)2u)])); 
    return; 
} 


struct l_struct.A *A::operator=(A const&)(struct l_struct.A *llvm_cbe_this, struct l_struct.A 
    *llvm_cbe_tmp__1) { 
    unsigned int llvm_cbe_tmp3; 

    llvm_cbe_tmp3 = *((&llvm_cbe_tmp__1->field1)); 
    *((&llvm_cbe_this->field1)) = llvm_cbe_tmp3; 
    return llvm_cbe_this; 
} 


void A::A(A const&)(struct l_struct.A *llvm_cbe_this, struct l_struct.A *llvm_cbe_tmp__2) { 
    unsigned int llvm_cbe_tmp3; 

    llvm_cbe_tmp3 = *((&llvm_cbe_tmp__2->field1)); 
    *((&llvm_cbe_this->field1)) = llvm_cbe_tmp3; 
    *((&llvm_cbe_this->field0)) = ((&_ZTV1A.array[((signed int)2u)])); 
    return; 
} 

Tada!注意它是如何在複製構造函數和默認構造函數中設置虛擬表指針的。希望這可以幫助。

+0

可以在Windows 7上運行Clang?我找不到MS窗口的任何下載。 – Southsouth 2012-01-14 15:52:23

+0

爲什麼「結構A」是以下生成的代碼的一部分 struct A { public: struct A; inline A(); ... } Southsouth 2012-01-14 16:02:46

0

對象查看工具(如objdumpdumpbin)可以爲您分解輸出對象文件。然後,您可以四處查看,看看針對您所關心的功能/方法發佈了哪些指令。

7

您可以使用調試器跟蹤代碼以查看發生了什麼。例如:

#include <string> 

struct A { 
    int a[100]; 
    char c; 
    std::string s; 
}; 

int main() { 
    A a; 
    A b(a); 
} 

在複製構造函數的構造'b'處設置斷點。在VC++ 6調試器,點彙編器輸出的是:

12:  A b(a); 
00401195 lea   eax,[ebp-1B0h] 
0040119B push  eax 
0040119C lea   ecx,[ebp-354h] 
004011A2 call  @ILT+140(A::A) (00401091) 

最後是拷貝構造函數調用。如果你想了解更多的細節,你也可以追蹤到。但是,如果你的問題是「我怎麼能看到複製構造函數等的C++代碼」,答案是你不能,因爲沒有任何 - 編譯器生成彙編器或機器代碼(取決於在你的編譯器上),而不是C++代碼。

-1

您確定您需要查看此功能嗎?

默認情況下,編譯器通過調用每個成員變量上的複製構造函數或賦值運算符來創建它們。

問題是,當您使用使用引用計數來管理數據的對象時,默認的複製構造函數將創建對象的副本,但不會創建對象指向的數據的副本。這也是指針的情況。所以如果你有類:

class aClass 
{ 
    int one; 
    int *ptwo; 
}; 

默認的複製構造函數只複製的數據a和指針b。但是他不復制b指向的數據。如果你,如果你想這個類,而不是複製指針ptwo的價值使用這個類像

aClass a, b; 
a.ptwo = new int; 
a.one = 1; 
*(a.ptwo) = 2; 

b = a; 

*(b.ptwo) = 1; 
//a.ptwo now points to an integer with the value of 1 

,你需要自己的拷貝賦值運算符的功能。如果你對更多的細節感興趣,那麼默認函數的作用是什麼以及什麼不是,那麼你可以看一下書「Effective C++」。
它有關於這個東西的整章,它解釋了什麼類的默認功能做什麼,不做什麼,他們應該做什麼,什麼時候寫你自己的。如果你只是想知道這個功能,我相信你可以在網上獲得一個數字版本。

2

編譯器生成的方法是抽象的,它們在源代碼中不存在。
看看下面的例子,我試着解釋一下編譯器生成的方法應該在源代碼級別執行什麼樣的四個。從這裏你應該能夠推斷任何普通班級。

如果你有一個這樣的類:

class X: public Base 
{ 
    int* a; 
    double b; 
    Y  c; 
}; 

那麼編譯器會生成以下等效:

X::X() // Default constructor 
    :Base() Calls the base class default constructor 
    //,a pointers are POD no default initialization 
    //,b double are POD no default initialization 
    ,c() //Call default constructor on each non POD member 
{} 

X::~X() // Default destructor 
{} 
// Destructor for each non POD member in reverse order 
~c()  calls the destructor of the class type 
//~b  double are POD no destructor 
//~a  pointers are POD no destructor 
~Base() // Calls the base class destructor 

X::X(X const& copy) 
    :Base(copy) // calls the base class copy constructor 
    // Copies each member using its copy constructor 
    ,a(copy.a)  // Pointers copied (Note just the pointer is copied, not what it points at) 
    ,b(copy.b)  // Double copied. 
    ,c(copy.c)  // Uses copy constructor of the class type (must be accessible) 
{} 

X& X::operator=(X const& copy) 
{ 
    Base::operator=(copy); // Calls the base class assignment operator 
    // Copies each member using the members assignment operator 
    a = copy.a; // Pointers copied (Note just the pointer is copied, not what it points at) 
    b = copy.b; // Double copied 
    c = copy.c; // Uses assignment operator of the class type (must be accessible) 

    return *this; 
} 
+0

另請參閱:http://stackoverflow.com/a/1810320/14065 – 2012-10-12 17:49:01

相關問題