2012-07-18 71 views
4

這幾天一直在掙扎。使用placement new來調用構造函數

問題是構造函數調用。

我寫像一塊代碼:

#include <iostream> 
using namespace std; 

class Foo 
{ 

    private: int _n; 

    public: 

    Foo() { Foo(5);} 

    Foo(int n) {_n=n; cout << n << endl; } 

}; 

int main() 
{ 
    Foo* foo = new Foo(); 
    return 0; 

} 

當我構造的Foo對象外使用默認構造:

Foo* f = new Foo(); 

我想可變_n爲5,然而,事實並非如此。

在Java中沒關係,但不在C++中。

另外,在Visual C++ 6 SP 6,

Foo() {this->Foo(5);} 

作品。

然而,該表達通過GCC拒絕/克++ 4.

最後,我發現瞭解決方案。

只需更改默認構造成

Foo() {Foo(5);} 

Foo() { new (this) Foo(5); } 

解決了這個問題。

圓括號中的「this」是做什麼用的?

+1

Googl ... err覆蓋了[C++ FAQ](http://www.parashift.com/c++-faq/index.html):[「一個類的一個構造函數可以調用另一個構造函數同樣的類初始化這個對象?「](http://www.parashift.com/c++-faq/init-methods.html) – 2012-07-18 18:45:45

+2

」在Java中沒關係,但不在C++中。「根據你對Java的瞭解,甚至不用費力去理解C++。它不但沒有幫助,而且實際上是有害的。 – 2012-07-18 18:46:55

+4

如果我沒有弄錯,解決這個問題的一個方法是不聲明'Foo()',而是將'Foo(int n)'聲明改爲'Foo(int n = 5)'。這樣,該構造函數可以用作默認值。這是一段時間,因爲我做了任何C + +編程,所以我可能是錯誤的那 – 2012-07-18 18:47:04

回答

0

在C++中正確的語法是

class Foo { 

    private: int _n; 

    public: 

    Foo() : Foo(5) {} 

    Foo(int n) _n(n) {} // As suggested by another member's edit, initializer lists are preferred 

}; 

另外,C++允許默認參數值,如

Foo(int n = 5); 

這允許你寫一個構造函數,而不是兩個。

另外,您應該確定瞭解內聯函數和非內聯函數之間的區別。這種Java風格的編程是有效的C++,但它有其優點和缺點,並至少有一個其他選擇。

+2

注意,這隻在C++ 11中有效。 – Xeo 2012-07-18 18:47:08

+0

@Xeo自從我用C++認真編程以來,這已經有一段時間了。我很確定我能夠在C++ 11之前從初始化程序列表中調用其他構造函數。不過,也許我的記憶力是錯誤的。 \ *聳肩\ * – 2012-07-18 18:50:40

+0

爲什麼這是低估,這是基本正確 – Philipp 2012-07-18 22:03:22

0
Foo() { new (this) Foo(5); } 

是一個「placement new」運算符,它在預分配的內存上調用構造函數。

現在,爲您提出其他問題 - C++ 11允許(從另一個調用構造函數),但較早的標準(特別是由MSVC 6使用的)沒有那麼那麼使用那些醜陋的init()方法是你去的方法。

3

在C++ 11你用委託構造函數中指定的:

Foo() : Foo(5) { } 
4

(this)做什麼,是創造了一個全新Foo對象,在發生在指向的this(這被稱爲放置新)。您應該只在charunsigned char的數組中使用它,在其他地方(幾乎從不在那裏)。由於您正在this已經開始構建的位置構建Foo,因此您所做的是未定義的行爲,如果您有基類,則會泄漏資源。從歷史上看,正常的做法只是將初始化移至私有函數。

class Foo { 
public:  
    Foo() { init(5);}  
    Foo(int n) {init(n);} 
private: 
    int _n; 
    void init(int n) { 
    _n=n; 
    }; 
} 

在C++ 11中,構造函數應該能夠用這種語法調用對方,但我不知道哪些編譯器支持它。 According to Apache,它支持GCC 4.7和Clang 3.0,但還沒有Intel C++和VC++。

class Foo { 
public:  
    Foo() : Foo(5) {} 
    Foo(int n) {_n=n;} 
private: 
    int _n; 
} 

你開始Foo() { Foo(5);}代碼開頭的this建設,然後創建堆棧與參數5上的全新Foo對象,然後摧毀它,然後認爲自己完全構建,而不初始化任何它自己的值。這就是它編譯和運行的原因,但似乎沒有做任何事情。

+0

每個人都錯過了他的代碼有一個錯誤的事實。他正在調用Foo(5)的構造函數,但臨時對象在塊的末尾被銷燬。 – 2012-07-18 18:58:25

+0

@ 0A0D:我注意到,但忽略它,我會編輯它來提及它 – 2012-07-18 19:05:27

+0

@ user195488:不,臨時對象在分號處被銷燬。 – jdh8 2014-08-04 07:15:19

1

括號內的(this)運營商將使用this的地址作爲地址initalize類。

這是危險:您在當前對象的構造函數中,並且在相同的內存空間上調用一個新的構造函數。 想象一下,如果你從另一個班級繼承,會發生什麼!

至於你的問題,你不能從構造函數中調用另一個重載的構造函數。 典型的解決方案是有一個方法來初始化類:

class Foo 
{ 
    int _n; 
public: 
    Foo() { init(5); } 
    Foo(int i) { init(i); } 
    void init(int i) { _n = i; } 
}; 

我已經在這兒住了同樣的問題:Yet another C++ Object initialization interrogation;隨時查看解決方案。