4

我想在 C++ 中使用动态数组(类似于 Java 中的 ArrayList 或 Vector。)
在此示例中,是复制 t1、t2... 对象还是仅将其地址添加到向量中?
我是否需要为 Node 类实现一个复制构造函数,或者默认构造函数会制作一个“正确”的副本(因为类中有一个指针)?
或者我应该只声明 avector<Node*>而不是 this 以避免复制?
我是否必须实现一个析构函数来删除other_node指针,或者它是否可以被程序使用并且仍然存储在vector

#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;
}
4

2 回答 2

4

在您的示例vector<Node>中,将存储节点的副本,因此t1,t2将被复制。

此外,默认的复制构造函数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因此不应将其删除。

性能方面,由于您的 Node 复制起来相当便宜(一个 int 和一个指针),所以存储一个副本是可以的。如果你的 Node 类做了一个深拷贝,那么从性能的角度来看使用会更好vector<Node*>

于 2010-07-23T22:23:22.590 回答
2

std::vector并且其他 C++ 标准库容器具有值语义,换句话说,它们期望保存实际对象而不是指向对象的指针。因此,每当您将对象放入标准库容器时,容器都会复制它。值语义具有某些含义,例如在容器销毁时自动清理会导致内存泄漏,如果您的容器持有指向对象的指针;在这种特殊情况下,您需要自己手动删除指向的对象。

我的建议是,如果您有复制成本低或复制成本高但不经常复制的对象,请将它们作为值放入容器中。如果您需要容器保存多态对象或经常复制,复制对象的成本很高,请使用 aboost::shared_ptr<>或使用适当的boost::ptr_xxx容器(如boost::ptr_vector.

于 2010-07-23T23:14:55.223 回答