2014-04-22 61 views
0

我一直在努力工作。無法調用指針的打印功能

我正在研究一個名爲「boxFactory」的函數,它將Box基類的指針返回給測試類。測試類然後從該指針調用打印功能。

現在我試圖在我工作其他類型之前打印方格框打印。但是,當我運行下面的代碼時,會在bptr-> print(os)處發生以下異常:

「Assignment.exe中0x0091C512處未處理的異常:0xC0000005:訪問衝突讀取位置0xCCCCCCD0」。從測試類

Box * boxFactory(char c, int w, int h){ 

Box * b; 

if(c == 'c') 
{ 
    CheckeredBox cb; 
    b = &cb; 
    b->setHeight(h); 
    b->setWidth(w); 

    return b; 
} 

return NULL; 
} 

代碼片段:

Box * bptr = boxFactory('c',5,3); 

// Check print #7 
os.str(""); //reset output holder 
bptr->print(os); 
t.test(os.str() == "x x x\n x x \nx x x\n", "print 5x3 checkered box from factory"); 

從派生類格子的打印功能:

ostream& CheckeredBox::print(ostream& os) const 
{ 
//HEIGHT for loop 
for (int i = 0; i < height_; i++) 
{ 
bool isX; //is current space x or blank 

//makes the every other line starts 
if (i % 2 == 0) 
{ 
    isX = true; 
} 
else 
{ 
    isX = false; 
} 

//WIDTH for loop 
for (int c = 0; c < width_; c++) 
{ 
    if (isX) //utilizes isX boolean 
    { 
     os << "x"; 
     isX = false; //oscilates bool between spaces 
    } 
    else 
    { 
     os << " "; 
     isX = true; //continues oscilation 
    } 
} 

os << "\n"; //append new line after each row 
} 

return os; 

} 

回答

1

你是返回一個指向一個局部變量。這是未定義的行爲。

if(c == 'c') 
{ 
    CheckeredBox cb; 
    b = &cb; 
    b->setHeight(h); 
    b->setWidth(w); 

    return b; 
} 

這裏cb超出範圍,一旦此功能使這個if但你返回其地址。使用此地址會導致「未定義的行爲」。你反而想在堆上分配一個對象然後返回它。像下面的東西。

b = new CheckeredBox(); 
+0

感謝您的快速響應。 – user3559406

+0

但是別忘了'delete' b:C++不會自動執行此操作。或者查看'std :: unique_ptr'或'std :: shared_ptr'。 – Bathsheba

2
if(c == 'c') 
{ 
    CheckeredBox cb; 
    b = &cb; 
    b->setHeight(h); 
    b->setWidth(w); 

    return b; 
} 

局部變量得到分配在堆棧中,當他們宣佈的代碼塊退出相同的內存空間將被用於將覆蓋它們的其他變量。

對於動態分配對象,請使用new運算符,該運算符將分配堆中的對象。這些對象將一直持續到您delete他們(不要忘了這樣做,否則你會得到內存泄漏

b = new CheckeredBox(); 
// etc. 
+0

謝謝,我完全理解內存如何工作仍然有一些問題。 – user3559406

3

您在boxFactory功能創建CheckeredBox對象的自動實例。所以當cb對象超出範圍(如果是block)時,它會被破壞,並且你正在返回被銷燬對象的地址。這就是爲什麼當你嘗試調用這個指針的打印方法時,你會得到'訪問衝突'錯誤。以下是你可以做什麼來完成你想要的。

您需要使用new關鍵字在堆上構造CheckeredBox對象,然後從boxFactory函數返回它。在這種情況下,您的應用程序可以正常工作,但問題仍然是誰應該刪除您在堆上創建的對象。你可以在你的函數文檔中指定調用者應該刪除返回的對象,但是如果你或者其他人使用你的代碼不夠小心,你的應用程序很可能會泄漏內存。 您可以使用std :: auto_ptr來獲取並轉移對象的所有權,以便它自動刪除。

std::auto_ptr<Box> boxFactory(char c, int w, int h){ 
    std::auto_ptr<Box> b; 

    if(c == 'c') 
    { 
     CheckeredBox *cb = new CkeckeredBox(); 
     cb->setHeight(h); 
     cb->setWidth(w); 
     b.reset(cb); 
    } 

    return b; 
} 

考慮的auto_ptr是新的C++ 11個標準,你可以使用boost :: shared_ptr的,性病::的unique_ptr(C++ 11只)或std :: shared_ptr的(C++ 11只),不推薦使用。