0

在做一个处理图论的项目时,我使用了这样的对象:

class Node{
vector<Node> nodeList;
};
Node n = new Node();
Node a = new Node();
n.nodeList.push_back(a);

在创建了大约 20 个节点后,每个节点平均有 3 个与其他节点的连接,我的程序基本上会挂起。

为了解决这个问题,我将对象声明更改为

class Node{
vector<Node*> nodeList;
};
Node* n = new Node();
Node* a = new Node();
n.nodeList.push_back(a);

我的程序立即通过 50 个节点运行 10 个连接。

第二个示例运行得更快,因为我只是添加指向列表的指针,而不是实际的节点,对吧?

但是 C++ 文档说new关键字返回一个指向创建对象的指针。为什么在第一个示例中将整个对象放入向量中,而不仅仅是指针?

C++ 中的标准是否有任何理由将整个对象复制到数据结构而不是指针中?

编辑:我很抱歉,你是对的,第一个例子不应该编译。我的驱动器上不再有第一个示例,我不记得确切的情况。对不起。

4

3 回答 3

3

C++ 中的标准是否有任何理由将整个对象复制到数据结构而不是指针中?

传统上,所有标准库容器类都使用Value Semantics而不是Reference Semantics
值语义意味着容器创建其元素的内部副本并返回这些元素的副本,而引用语义意味着容器包含对其元素的对象的引用。最明显的方法是使用指针作为容器元素来实现这一点。标准库使用值语义,因为:

  • 实现值语义更简单。
  • 引用语义可能容易出错。需要处理在容器元素的生命周期中始终有效的实际对象。
  • 如果需要明确的引用语义,那么他们可以选择使用指针作为容器元素来实现。

您展示的第一个代码示例无法按原样工作。任务使用new指针。因为这个指针需要指向freestore上的对象。具有非指针数据类型的对象不能这样做。可能,您在代码中所做的是将派生类对象分配给基类对象,从而导致Object slicing


如果您确实需要引用语义,那么使用智能指针作为容器元素而不是您现在使用的原始指针是一个好主意。

于 2013-05-10T05:29:38.160 回答
1

但是 C++ 文档说 new 关键字返回一个指向创建对象的指针。为什么在第一个示例中将整个对象放入向量中,而不仅仅是指针?

它没有,这段代码:

class Node{
vector<Node> nodeList;
};
Node n = new Node();
Node a = new Node();
n.nodeList.push_back(a);

根本不会编译,您不能分配指向值或引用变量的指针。

向量将保存您在模板参数中指定的任何内容,可以是指针或整个对象(byVal):

vector<Node> nodeList;

此向量将是 Node 对象的集合(按值),您只能按值推回 Node 对象。

vector<Node*> nodeList;

这是一个Node类型的指针向量,你只能推回node类型的指针。

于 2013-05-10T05:24:09.063 回答
1

但是 C++ 文档说new关键字返回一个指向创建对象的指针。为什么在第一个示例中将整个对象放入向量中,而不仅仅是指针?

可能不是......唯一Node a = new Node();可以编译的方法是如果有一个Node(Node*)orNode(const Node*)构造函数,Steven 可能现在已经告诉我们了。

所以 - 我最近的 SO 口头禅 - '向我们展示代码否则它没有发生'。;-P

C++ 中的标准是否有任何理由将整个对象复制到数据结构而不是指针中?

容器被设计为具有值语义。这是非常灵活的,因为如果适合您的目的,您可以选择在容器中包含原始或任意多个智能指针。如果容器被设计为提取和存储指向正在push_back()编辑的对象的原始指针,那么将会有更多的决策和必要的低效率。例如,一个doubles 或ints 的容器不想将每一个间接存储在单独的(非连续的)堆内存中——这会对性能造成很大的影响。

于 2013-05-10T05:33:50.147 回答