2015-05-13 69 views
0

我不是100%肯定我措辭標題爲這個權利,使這裏就是我希望能夠做到......如何在C++中初始化一個對象?

我有被像這樣定義的類...

class Animal 
{ 
public: 
    Animal() : m_name("New Animal") 
    { 
    } 

    Animal(const std::string& name) : m_name(name) 
    { 
    } 

    Animal(const Animal& animal) : m_name(animal.name) 
    { 
    } 

private: 
    const std::string name; 
}; 

我然後初始化這個類的一個對象,像這樣......

Animal* m_animal = new Animal("Leroy"); 

我在程序的某個時刻,用戶會點擊一個按鈕,將導致m_animal變空。這意味着名爲Leroy的寵物不應該存在..

我假設我可以使用刪除m_animal,但是一旦我調用此函數,我就不能再使用m_animal而不會導致內存分配錯誤。

所以我想我的問題是... 我會使用下面的代碼導致內存泄漏,因爲名爲Leroy的寵物沒有被刪除...如果是的話,如何做到這一點的替代方案?

m_pet = NULL; 

整個過程是這樣的......

Animal* m_animal = new Animal("Leroy"); 
Animal* m_animal2 = new Animal("Boo"); 
std::cout << m_animal.name << endl; 
m_animal = NULL; 
m_animal = new Animal(m_animal2); 
std::cout << m_animal.name << endl; 
+1

是的,這是一個內存泄漏 – James

+0

使用'm_animal-> name'而不是'm_animal.name',因爲它的指針。 –

回答

4

要使用delete m_animal;。你可以這樣做:

std::cout << m_animal.name << endl; 
delete m_animal; 
m_animal = new Animal(m_animal2); 
std::cout << m_animal.name << endl; 

調用delete m_animal後,可以不再使用什麼m_animal指出,但你當然可以再次使用m_animal指針。

+2

刪除後應該將m_animal設置爲nullptr/NULL,否則最終會出現雙重刪除情況。 OP應該可能使用shared_ptr。 – James

+4

@詹姆斯:代碼沒有問題,因爲我給了它;在這種情況下'm_animal'在刪除後立即被分配一個新值。但是,如果你不打算立即給這個指針一個新的值,那麼是的,分配NULL值會很有用。 –

+0

工作很好,只有我現在有的問題是... \t 所以在我的例子中,當我從m_animal2創建一個新的動物...如果我不再使用m_animal2,我必須使用刪除m_animal2嗎? – Ricky

0

如果您創建具有new操作的對象,那麼你就需要與運營商delete刪除它。

Animal* animal = new Animal("Pig"); 

// Using the animal ... 

delete animal; 
animal = nullptr; 

您需要使用new - delete對以避免內存泄漏。

+0

所以在我的例子中,當我從m_animal2創建一個新的動物...如果我不再使用m_animal2,我必須使用刪除m_animal2嗎? – Ricky

+0

是的,當你不想再使用時需要刪除它。 –

2

你可以只添加一個clear成員函數(例如)將名稱設置爲空字符串。這意味着「Leroy」不再存在,但存在有效狀態的Animal,因此您可以使用它來保存其他動物而不刪除舊動物並分配新動物。

然而,這仍然留下Animal對象 - 只是一個沒有名字。如果要將分配與創建/銷燬內存中的對象分開,可以使用operator new分配原始內存,然後使用新的放置位置在內存中創建對象。當你想銷燬對象時,你可以直接調用它的析構函數,這會真正銷燬對象(但保留分配的內存)。

當你與內存中完成,你可以使用operator delete刪除存儲。

旁白:其實這就是什麼std::vector,舉一個例子,確實有它的內存塊。雖然它可能是更多在處理多個對象時很有用,但對於單個對象也沒有特別的錯誤。

除了#2:在大多數情況下,您不需要(或真的想)直接使用newdelete,如上所示。在相當多的情況下,您可以使用std::shared_ptrstd::unique_ptr代替std::make_sharedstd::make_unique分配對象。

+0

我的不好 - 我沒有正確閱讀你的第1段...對於重複的答案抱歉。 +1偉大的頭腦和所有。 –

+0

但是,如果您選擇使用此方法,請記住您不得在其他任何地方提供該對象,因爲將該對象重新用於其他動物也會更改指向其他地方的對象。特別是作爲初學者,每次只使用新對象可能會更好。 –

0

由於這兩個指向Animal類。這應該工作太:

std::cout << m_animal->name << endl; 
m_animal = m_animal2; 
std::cout << m_animal->name << endl; 

無需對動物第三次分配內存,即使其中一個被刪除之前,其低效的代碼。那麼你應該只刪除這些指針中的一個,並將它們都設置爲nullptr。不過,使用std::shared_ptr可能是一個更強大的解決方案。

1

有時(但不是這個mcve),使用init()方法更簡單。

雖然我更喜歡如您在此處使用(在構造函數之後)的初始化列表中,你有時會碰到系統啓動順序選項在構造函數的參數是尚未公佈,因此無法通過填寫ctor。當兩個或多個實例(相同或不同類)指向另一個實例(如在工作和保護硬件控制時)時,這是一個特殊問題。因此,您可能會考慮以下問題,它解決了排序和相互依賴性問題通過提供一個init()方法。

class Animal 
{ 
public: 
    Animal() 
    { 
     init("New Animal") 
    } 

    Animal(const std::string name) 
    { 
     init(name); 
    } 

    Animal(const Animal& animal) 
    { 
     init(animal.m_name); 
    } 

    void init(std::string name) 
    { 
     m_name.erase(); // clear the previous attribute 
     //   (not really needed here, but included for clarity) 
     m_name = name; // fill in new attribute 

     // and continue with both clear (when needed) and init's 
     // of all the other data attributes 
     // in an order similar to the initialization list. 
     // note that the compiler won't be able to notify you 
     // of out of order initialization issues. 
    } 

private: 
    const std::string name; 
}; 

那麼,是init()適合什麼嗎?

你問

我怎麼未初始化的對象。

在這種情況下,你可以簡單地使用 「的init(...)」 同時

一)清除掉以前的狀態信息(必要時)時

B)初始化狀態信息彷彿新建

C)避免相對昂貴的刪除和新的其他辦法。