2013-07-23 67 views
0

創建對象,我正在學習如何操縱與C函數對象++,到目前爲止,我已經得出以下觀點:功能在C++

如果你的對象是潛在的大,不讓它一局部變量,即將其保存在堆中以節省複製時間。

具體來說,我感興趣的是我們正在使用一個函數來創建一個以前不存在的對象的場景。 我已經把下面的小例子來展示該怎麼做,如果你有一個函數:

#include <iostream> 
using namespace std; 

struct obj { 
    int first; 
    int second; 
}; 


void setFirstVersionA(int a, obj * s) 
{ 
    s->first = a; 
} 

obj * setFirstVersionB(int a) 
{ 
    //in Version B I am creating a new object in the function but have to run delete outside 
    obj * s = new obj(); 
    s->first = a; 
    return s; 
} 


int main(int argc, const char** argv) 
{ 
    obj * myobj = new obj(); 
    setFirstVersionA(2,myobj); 
    //now I have the new obj in *i 
    cout << myobj->first; 
    delete myobj; 

    //this is an alternative to passing a pointer directly: 

    //no need to re-declare the pointer as delete only erases the myobj data 
    myobj = setFirstVersionB(3); 
    //now I have the new obj in *i 
    cout << myobj->first; 
    delete myobj; 

    return 0; 
} 

據我所知,這兩個功能實現同樣的結果。

我喜歡版本A更好,因爲它不會區分新聲明和刪除聲明,並且使得我完成後不會輕易忘記刪除對象。但是它是一個返回類型void,我發現代碼的可讀性較差,因爲我必須真正檢查函數的功能(通常它意味着讀取其他文件)。

我更喜歡版本B,因爲它返回了我想改變的「事情」。所以我立即知道,這個函數改變了那個人(在這個例子中是obj)。但它分開,新建和刪除。誠實地說,我發現比在我的代碼中有一系列無效函數並沒有立即看到他們做什麼更可怕。 另外,這裏寫了很多關於不返回指向局部變量的指針,但是在變體B中,儘管對象是在函數內創建的,但它不是局部變量(因爲它位於堆中)。對?

有沒有更好的方法來做到這一點?另外,「創建一個以前不存在的對象的函數」聽起來很像構造函數。 :)我應該可能創建一個類與我的每個對象的構造函數?

感謝您的諮詢!

+1

您應該閱讀關於智能指針,以及關於通過引用傳遞對象。 – Antonio

+2

您應該詳細閱讀[返回值優化](http://en.wikipedia.org/wiki/Return_value_optimization),並且C++ 11移動語義。 – juanchopanza

+1

此外,顯然,從@安東尼所說的,你還應該檢查RVO和NRVO。順便說一下,如果你的可讀性問題可以從第一個函數返回,那麼你總是可以返回'obj *'。 – lapk

回答

3

正確的方法很可能是要麼建立一個構造函數的值作爲參數:

struct obj 
{ 
    obj(int f) : first(f) {} 
    // ... 
}; 

// ... 

obj myobj(2); 

還是有一個setter函數:

struct obj 
{ 
    void set_first(int f) { first = f; } 
    // ... 
}; 

// ... 

obj myobj; 
myobj.set_first(2); 

上述方法當然可以合併,所以你們都有專門的構造函數和setter方法。

雖然setter方法可能會被跳過,因爲您正在使用只有公共成員變量的結構。

+1

我會建議添加爲什麼這是「正確」的方式? – Pedrom

3

您應該忽視您找到的建議,在堆棧中分配對象,然後按值返回。 C++特別是C++ 11具有特定的優化來提高效率:複製elision(各種情況允許編譯器像兩個對象實際上一樣)並移動語義(在C++ 11中爲新的,允許編譯器識別不再需要舊對象並執行比複製更高效的情況)。

+0

非常有趣,所以基本上你是說在這個特定的例子中,我可以忘記指針,按值返回對象,編譯器會優化代碼以像指針一樣快地運行? –

+0

通常是 - 移動語義幫助,並取決於編譯器。如果你有'默認'關鍵字支持,你也可以進一步的巧妙優化 – Ronnie

1

由於您正在學習C++,因此我建議您學習C++ 11。在這種情況下,你應該真的在考慮智能指針(比如std :: unique_ptr),或者更多地考慮在堆棧上創建項目,並讓編譯器負責自動銷燬 - RAII(資源獲取是初始化)原則。

這樣你就可以避免你的新的/刪除潛在的內存泄漏,並創建更可靠的代碼。

創建對象的函數通常是一個工廠,所以稍後您可能會想要查看boost:value_factory>作爲更簡單的方法。

+0

根據https://en.wikipedia.org/wiki/Smart_pointer,我認爲unique_ptr出現在C++ 11中?也許不會? – Ronnie

+1

而且這兩個unique_ptr變體都僅標記爲C++ 11。該標記不僅適用於Deleter參數。 unique_ptr在C++ 11中是新的,這很有意義,因爲它依賴於移動語義,這也是新的。 –

+0

嗯,是的,對不起,你是對的,我錯了:我很困惑unique_ptr與(現在不贊成)auto_ptr – Antonio

2

我想你來fram Java世界(obj * myobj = new obj();語法) 這是正確的C++,但你不應該使用指針,當它不是必要的。

一個更好的(IMO)計算策略是這樣的:

int main(int argc, const char** argv){ 
    Obj myObject; // your object now exists, fully usable. 
    myObject.setValue(42); //classic, java-like setter 

    Obj mySecondObect(42); //even better when you know the value at construct time. 
} 

爲obj中的點閱率就是看起來像:

Obj::Obj(int myValue) : _myVal(myvalue){} 
在這種情況下

,你attribut是在構造函數體前初始化(見C++構造函數循環)。