2012-04-16 56 views
2

我想從一個函數作爲輸出參數返回一個對象,但對象沒有默認構造函數,因此我不能做到這一點:返回構造無對象作爲輸出參數

bool FindFlaggedObject(MyObject& myObject) 
{ 
    std::vector<MyObject> myObjects = GetSomeObjectList(); 
    for (UINT i = 0; i < myObjects.size(); i++) 
    { 
     if (myObjects[i].Flag) { 
      myObject = myObjects[i]; 
      return true; 
     } 
    } 
    return false; 
} 

void main() 
{ 
    MyObject myObject; // NOT ALLOWED - OBJECT HAS NO DEFAULT CONSTRUCTOR 
    if (FindFlaggedObject(myObject)) 
    { 
     ... 
    } 
} 

所以,看起來像我應該回到它的堆,並與一個shared_ptr實例管理它,就像這樣:

bool FindFlaggedObject(MyObject& myObject) 
{ 
    std::vector<MyObject> myObjects = GetSomeObjectList(); 
    for (UINT i = 0; i < myObjects.size(); i++) 
    { 
     if (myObjects[i].Flag) { 
      myObject = new MyObject(myObjects[i]); 
      return true; 
     } 
    } 
    return false; 
} 

void main() 
{ 
    MyObject* myObjectPtr; 
    if (FindFlaggedObject(myObjectPtr)) 
    { 
     std::shared_ptr<MyObject> myObject(myObjectPtr); 

     ... 
    } 
} 

的缺點是,任何人都調用該方法必須記住,他是負責釋放的對象。
返回無構造函數的對象作爲輸出參數的最佳做法是什麼?

+0

當你說「無構造函數的對象」時,你是指「不可複製構造的對象」嗎?如果不是,物體從哪裏來? – Andre 2012-04-16 15:07:54

+0

@安德烈:對不起,對象是內部構造的(例如,通過朋友類)。它們確實有一個拷貝構造函數,但沒有無參數的構造函數,因此在調用方法之前很難在堆棧上進行分配。 – drifter 2012-04-16 15:31:06

回答

0

不需要使用默認構造函數構造自動對象。 只需傳遞構造函數參數。

void main() 
{ 
    MyObject myObject (12); 
    if (FindFlaggedObject(myObject)) 
    { 
    ... 
    } 
} 

另一方面,爲什麼不這樣做呢?

MyObject FindFlaggedObject() 
{ 
std::vector<MyObject> myObjects = GetSomeObjectList(); 
for (UINT i = 0; i < myObjects.size(); i++) 
{ 
    if (myObjects[i].Flag) { 
     return myObjects[i]; 
    } 
} 
return 0; 
} 

void main() 
{ 
    MyObject* res = FindFlaggedObject(); 
    if (res != 0) { 
     ... 
    } 
} 

你不必關心刪除資源只要資源仍然成員GetSomeObjectList

3

而不是返回bool並傳遞一個參考的有函數返回一個智能指針,確保呼叫者不會忘記釋放:

std::shared_ptr<MyObject> myObjectPtr = FindFlaggedObject(); 
if (myObjectPtr) 
{ 
    // Found flagged object. 
} 

std::shared_ptr<MyObject> FindFlaggedObject() 
{ 
    MyObject* result = nullptr; 
    std::vector<MyObject> myObjects = GetSomeObjectList(); 
    for (UINT i = 0; i < myObjects.size(); i++) 
    { 
     if (myObjects[i].Flag) { 
      result = new MyObject(myObjects[i]); 
      break; 
     } 
    } 
    return std::shared_ptr<MyObject>(result); 
} 
+0

這需要動態分配一個對象,這可能是一個昂貴的操作。 – 2012-04-16 15:10:51

+0

謝謝。如果它是一個庫函數,你會使用這種方法嗎? – drifter 2012-04-16 15:14:52

+0

我不確定你的意思是@drifter? – hmjd 2012-04-16 15:16:09

1

而不是使用out參數,返回一個值。由於該值是可選的,由布爾的電流返回類型所指出,你可以使用boost::optional用於這一目的:

boost::optional<MyObject> FindFlaggedObject() 
{ 
    std::vector<MyObject> myObjects = GetSomeObjectList(); 
    for (UINT i = 0; i < myObjects.size(); i++) 
    { 
     if (myObjects[i].Flag) { 
      return myObjects[i]; 
     } 
    } 
    return boost::none; 
} 
+0

+1使用'boost :: optional',它描述了這裏最好的東西。 – Andre 2012-04-16 15:15:11

5

返回的值幾乎總是最好的解決方案,如果該對象 支持拷貝(和對象,其將在棧上聲明應該 一般支持複製)。如果函數可能會失敗,而不是一味 返回一個對象,你可以使用某種FallibleMaybe類:

Fallible<MyObject> 
FindFlaggedObject() 
{ 
    std::vector<MyObject> objects = GetSomeObjectList(); 
    std::vector<MyObject>::const_iterator current = objects.begin(); 
    while (current != objects.end() && !current->flag) { 
     ++ current; 
    } 
    return current == objects.end() 
     ? Fallible<MyObject>() 
     : Fallible<MyObject>(*current); 
} 

您可能反映,雖然:如果GetSomeObjectList()可以隨時返回 參考的現有的列表(而不是構建一個列表 內部),並修改它返回一個const引用,你可以 只返回一個指針:

MyObject const* 
FindFlaggedObject() 
{ 
    std::vector<MyObject> const& objects = GetSomeObjectList(); 
    std::vector<MyObject>::const_iterator current = objects.begin(); 
    while (current != objects.end() && !current->flag) { 
     ++ current; 
    } 
    return current == objects.end() 
     ? NULL 
     : &*current; 
} 

這是一個非常典型的C++成語。

+0

我想補充一點,如果'GetSomeObjectList'不是引用透明的,那麼這個成語可能會導致懸掛指針。所以,我會建議使用shared_ptr(與其他人一樣)。 – Andre 2012-04-16 15:13:29

+0

@James:如果對象必須或應該返回輸出參數會怎麼樣? – drifter 2012-04-16 15:28:20

+0

@Andre'shared_ptr'是可以想象的最糟糕的解決方案。它需要動態分配,並在客戶端代碼中使用'shared_ptr',而'shared_ptr'則很少適用。如果對象不是引用透明的(他的名字'GetSomeObjectList'表明它應該是),那麼'Fallible '實際上是唯一有效的解決方案。 – 2012-04-16 15:43:32

相關問題