2015-08-13 155 views
0

我在BirdHouse的構造函數初始化列表中初始化指向Bird的指針時遇到問題。它似乎並不指向我想指向的對象。指針初始化到構造函數C++中的不同類

這裏是鳥類:

class Bird 
{ 
    std::string name; 
    static int objectCount; 
public: 
    Bird() : name("Bird #" + std::to_string(objectCount)) 
    { 
     ++objectCount; 
    } 

    Bird (const Bird& bb) : name(bb.name + " copy") 
    { 
    } 

    friend class BirdHouse; 
}; 

這裏是禽舍類:

class BirdHouse 
{ 
    Bird b; 
    Bird * bp; 
    Bird & br; 
public: 
    BirdHouse(Bird aa, Bird bb, Bird cc) : b(aa), bp(&bb), br(cc) {} 

    void print() const 
    { 
     std::cout << "Bird b = " << b.name << std::endl; 
     std::cout << "Bird * bp = " << bp->name << std::endl; 
     std::cout << "Bird & br = " << br.name << std::endl; 
    } 
}; 

當我想打電話給禽舍::打印()在main()程序崩潰:

int main() 
{ 
    Bird b1; 
    Bird b2; 
    Bird b3 = b2; 

    BirdHouse bh1(b1,b2,b3); 
// bh1.print(); // I can't call it because b2 points to weird stuff 

    return 0; 
} 

我應該如何初始化BirdHouse對象,使其指向適當的Bird對象?

回答

4

的崩潰是因爲未定義行爲,因爲你保存一個指針是按值傳遞的參數,一旦函數返回,該對象將被銷燬。

有兩種可能的解決方案,我可以看到它:將變量作爲指針傳入,或者通過引用傳遞它。但是,請小心,因爲如果對象的生命週期比傳入的對象(作爲指針或引用)的生命週期長,則您將再次發生未定義的行爲。

1
BirdHouse(Bird aa, Bird bb, Bird cc) : b(aa), bp(&bb), br(cc) {} 

aabbcc是由值傳遞的參數,它是局部的構造函數。但是,您存儲指向bb的指針以及對cc的引用,這兩者在構造函數結束時都會變得懸而未決。

當您嘗試訪問print()中的一個懸掛成員時,觸發未定義行爲,在您遇到崩潰的情況下。不要這樣做。

打開編譯器警告可能會通知您這個問題。

1
BirdHouse(Bird aa, Bird bb, Bird cc) : b(aa), bp(&bb), br(cc) {} 

在這裏您可以通過值獲取參數,從而創建副本。然後你繼續存儲一個指針並引用這些副本,這些副本將在構造函數的最後被銷燬。現在,只要您嘗試訪問這些,就會調用未定義的行爲。

爲了解決這個問題,你可以把你的參數通過引用來代替:

BirdHouse(Bird& aa, Bird& bb, Bird& cc) : b(aa), bp(&bb), br(cc) {} 
1
BirdHouse(Bird aa, Bird bb, Bird cc) : b(aa), bp(&bb), br(cc) {} 
//     ^^^^^^^, this is a temporary object (i.e., it won't exist 
//       after the constructor completes 

你上面的地址是一個臨時參數。如果您嘗試在構造函數的主體中使用bp。但是,一旦構造函數完成臨時對象消失,但bp仍然指向該內存地址。最後,一旦執行了print函數,它將取消引用不再指向有效對象的指針,並且行爲未定義。

根據您的使用情況,你可以改變你的構造函數是:

A)

BirdHouse(Bird aa, Bird& bb, Bird& cc) : b(aa), bp(&bb), br(cc) {} 

B)

BirdHouse(Bird aa, Bird* bb, Bird& cc) : b(aa), bp(bb), br(cc) {} 

注:它需要對呼叫者清​​楚的生命期和br需要持續至少與BirdHouse實例的生命週期一樣長。

+0

請注意,我們不知道是否存在所有權轉讓 - 可能不是,在鳥屋的情況下;) – Quentin

+0

@Quentin是的,我同意所有權在這種情況下沒有意義,但我認爲這是一般有用的信息,但也許它只是混淆了答案。 –