2010-07-23 108 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)将它们容纳在容器中。