2010-07-23 196 views
4

我想在C++中使用動態數組(如ArrayList或Java中的Vector)
在此示例中,是否將t1,t2 ...對象複製或只將其地址添加到向量中?
我是否需要爲Node類實現一個拷貝構造函數,或者默認的構造函數是否會創建一個「正確的」拷貝(因爲這個類中有一個指針)?
或者我應該聲明一個vector<Node*>而不是這樣來避免複製?
我是否必須實現一個析構函數來刪除other_node指針,或者它可以被程序使用並仍然存儲在vectorC++矢量複製元素?

#include <vector> 

using namespace std; 

class Node { 
public: 
    int id; 
    Node* other_node; 
}; 

int main(int argc, char** argv) { 
    vector<Node> nodes; 
    Node t1; 
    t1.id = 0; 
    t1.other_node = NULL; 
    Node t2; 
    t2.id = 1; 
    t2.other_node = &t1; 
    Node t3; 
    t3.id = 2; 
    t3.other_node = &t2; 
    Node t4; 
    t4.id = 3; 
    t4.other_node = &t1; 
    nodes.push_back(t1); 
    nodes.push_back(t2); 
    nodes.push_back(t3); 
    nodes.push_back(t4); 
    for (vector<Node>::iterator it = nodes.begin(); it != nodes.end(); it++) { 
     if (it->other_node) { 
      printf("%d (other.id: %d)\n", it->id, it->other_node->id); 
     } else { 
      printf("%d (other.id: NULL)\n", it->id); 
     } 
    } 
    getchar(); 
    return 0; 
} 
+1

只是一個提示,因爲你使用'std :: vector',你應該更喜歡'std :: cout'。 – Alan 2010-07-23 22:25:58

回答

4

在您的例子vector<Node>將存儲您的節點的副本,所以t1t2將被複制。

另外,Node的默認拷貝構造函數將會生成一個「淺」副本。因此

Node* head = new Node(); 
Node* next = new Node(); 
head->other_node = next; 
Node* other_head = new Node(*head); 

*(other_head->other_node)是在同一個節點*(head->other_node)它是由你來決定,如果這是你想要的行爲。

關於析構函數:除非您有充分的理由來獲取內存所有權,否則應該只刪除/釋放您的類實例分配的內存。對於你的列表,一般來說,因爲你的列表沒有分配other_node所指的內存,所以不應該刪除它。

表現明智,因爲您的節點是複製(int和指針)相當便宜,存儲副本是好的。如果您的Node類做了深刻的副本,那麼這將是從性能的立場來看,最好使用vector<Node*>

2

std::vector和其他C++標準庫容器都值語義,換句話說,他們希望保持實際的對象,而不是指針對象。因此,無論何時將對象放入標準庫容器中,容器都會將其複製。價值語義具有一定的含義,如自動清理容器導致內存泄漏的容器銷燬,如果您的容器持有指向對象的指針;在這種特殊情況下,您需要自己手動刪除指向的對象。

我的建議是,如果您的對象既不便於複製又不便於複製,但不經常複製,則將它們作爲值放入容器中。如果您需要容器容納多態對象或經常複製,複製對象的代價高昂,請使用boost::shared_ptr<>或使用適當的boost::ptr_xxx容器(如boost::ptr_vector)將它們容納在容器中。