我想做的一个小例子。
我有一个(堆栈分配的)顶点列表
class Vertex {
int id;
double x;
double y;
double z;
};
,想要创建一个边列表
class Edge {
int id;
Vertex * source;
Vertex * target;
};
,其中两个指针指向其源顶点和目标顶点。
通常我会在这里寻求参考,但我希望能够在运行时更改源或目标顶点,所以我需要某种指针类型。
所以我的问题是:是否有一个智能指针在这里有用,或者我应该像上面那样使用普通指针?
编辑
解决答案中出现的一些问题:
首先,列表应该拥有顶点,这就是它们位于堆栈上的原因。
其次,这些 ID 是用于其他程序的。
它需要一个文件,其中包含所有顶点及其坐标的列表,以及所有边及其两个顶点的 id 的列表。
第三,我需要某种指针,因为顶点的 id 在运行时会发生变化,并且边的源顶点和目标顶点可能会发生变化。
(除其他外,还执行某种切割和切片)
A little example of what I want to do.
I have a list of (stack allocated) vertices
class Vertex {
int id;
double x;
double y;
double z;
};
and want to create a list of edges
class Edge {
int id;
Vertex * source;
Vertex * target;
};
with two pointers to its source and target vertex.
Normally I would go for a reference here, but I want to be able to change the source or target vertex during runtime, so I need some kind of pointer type.
So my question: is there a smart pointer which would be useful here or should I just use a normal pointer as above?
Edit
Addressing some points, which came up in the answers:
First, the list should own the vertices, which is why they are on the stack.
Second, the ids are for an other program.
It needs a file with a list of all vertices and their coordinates, and a list of all edges and the ids of its two vertices.
Third, I need some kind of pointer, because the ids of the vertices change during runtime and the source and target vertex of a edge could change to.
(amongst other things some kind of cuts and slicing is performed)
发布评论
评论(5)
什么是组合
组合(用 UML 术语) 是一个关联,当一个给定的对象是另一个对象的“一部分”时,即它具有相同的生命周期,并且 - 最重要和特征是什么 - 本身不存在/有意义。
根据这个描述,组合不是我们想要实现的 - 请参阅第二部分。
在 C 或 C++ 中,实现组合的最佳方法是不使用任何指针:
这种方法在以下方面是最好的:内存使用(整个对象以及复合对象的一个内存块)以及可能的效率。当您需要构图时,请选择此解决方案。
为什么组合不适合这个问题
组合意味着一些后果:
在您的数据模型中,您有单独的:
两者都可能是堆栈分配的(但这并不重要)。
然后您希望每条边引用 N 个顶点。
边缘并不拥有它们——它只是引用它们。因此,组合或智能指针(旨在引入某种所有权关联)都不是您想要的,因为设计表明顶点由顶点数组拥有,而不是由边拥有< /em>。
所以选择一个普通的指针。
您甚至可以使用数组索引代替指针作为替代方案(这确实有其用途,例如,如果您想使用后一个数组作为 3D 渲染的索引缓冲区)。一切都取决于您的需求。
What Composition is
Composition (in UML terms) is an association when a given object is "a part" of another objects- i.e. it has the same lifetime and - what's most important and characteristic - does not exist / make sense on its own.
According to this description, composition is not what we want to achieve - see the second part.
In C or C++, the best way to implement composition is without using any pointers:
This approach is best in terms of memory usage (one memory block for the whole object along with composite objects) and probably efficiency too. When you need composition - go for this solution.
Why Composition isn't suitable for this problem
Composition implies some consequnces:
In your data model, you have separate:
Both possibly stack-allocated (but that's not really important).
Then you want each edge to refer to N vertices.
The edge does NOT own them - it only does refer to them. So neither composition, nor a smart pointer (which is designed to introduce some kind of ownership association) is not what you want here, because the design says that the vertices are owned by the array of vertices, not by the edges.
So go for a plain pointer.
You could even use array indices instead of pointers as an alternative (which indeed has its uses, e.g. if you'd want to use the latter array as an index buffer for 3D rendering). All depends on your needs.
一般来说,智能指针之所以“智能”,是因为它们处理所涉及的所有权问题。在上面,您希望谁拥有顶点?
Generally speaking, smart pointers are "smart" because they deal with the ownership issues involved. In the above, who do you want to own the vertices?
使用普通指针。如果指向的对象是在堆栈上分配的,那么智能指针就没有那么有用了。
如果您从长远来看担心安全性和边界检查等问题,请按每个
Vertex
的 id 排序(例如,决定0<=id,然后您可以有一个大小为 n 的数组),并将 id 存储在 Edge 而不是指针中。然后您可以使用
assert
或其他方式来检查 id 是否在合法范围内。Use a normal pointer. If the pointed-at objects are allocated on the stack, a smart pointer won't be all that helpful.
If you are concerned in the longer run about safety and bounds checking and so on, order each
Vertex
by its id (e.g., decide0<=id<n
, then you can have an array of sizen
), and store the ids in theEdge
rather than the pointers. Then you can use anassert
, or whatever, to check that ids are in the legal range.这是谁拥有指针的问题。如果您的 Edge 类拥有它们,那么您可以使用 auto_ptr。但是,您说您的 Vertex 对象是在堆栈上分配的,因此在这种情况下不需要显式清理,因为当它们超出范围时它们将被删除。
It's a question of who owns the pointers. If your Edge class owns them then you can use an auto_ptr. However, you say that your Vertex objects are allocated on the stack so there's no real need for explicit clean-up in this scenario, as they'll be deleted when they go out of scope.
这是通常的权衡:智能指针会更安全但速度更慢。使用 Boost 的
shared_ptr
如果你想走那条路。对于“业务逻辑”,我强烈提倡使用智能指针。但看起来您可能正在进行 CPU 密集型图形处理,这就是速度可能是重要因素的情况之一。所以我建议:
使用它进行调试,并在一切正常时切换
//
以提高速度。注意:如果顶点有可能指向指向它的边,事情就会变得更加复杂 - 您将需要对其中一个指针使用
weak_ptr
以避免循环引用。It's the usual tradeoff: a smart pointer will be safer but slower. Use Boost's
shared_ptr
if you want to go that way.For "business logic", I would strongly advocate using smart pointers. But it looks like you may be doing CPU-intensive graphics processing, which is one of the cases where speed may be an important factor. So I suggest:
Use this for debugging, and switch the
//
when everything's working for a speed boost.NOTE: If there is any possibility that a vertex may point back to an edge that points to it, things get more complicated -- you will need to use
weak_ptr
for one of the pointers to avoid circular references.