4

我目前正在手动管理项目中对象的生命周期。我正在考虑切换到智能指针,特别是 tr1::shared_pointer 和 tr1::weak_ptr。但是,我看到了一些问题,并希望获得有关最佳实践的一些意见。

考虑下面的类图:

多面体类图

在此图中,粗箭头表示与所有权语义的关联(源负责删除一个或多个目标)。细箭头表示没有所有权的关联。

据我了解,实现与所有权语义关联的一种方法是使用 tr1::shared_ptr (或其集合)。其他关联可以使用 tr1::shared_ptr 或 tr1::weak_ptr 来实现。如果前者可能导致循环引用,则禁止前者,因为这会妨碍资源的正确释放。

如您所见,Edge 和 Side 类之间存在一圈关联。我可以通过使用 tr1::weak_ptrs 实现从 Edge 到 Side 的“左”和“右”关联来轻松打破这一点。但是,我更喜欢使用智能指针在代码中记录关联的所有权语义。所以我想将 shared_ptrs 仅用于图中粗箭头表示的关联,而将 weak_ptrs 用于其他所有内容。

现在我的第一个问题是:我应该像上面描述的那样自由地使用weak_ptrs,还是应该尽可能少地使用它们(只是为了避免循环引用)?

下一个问题是:假设我有一个计算一组顶点平均值的函数。进一步假设我已经实现了从多面体到它的顶点的关联,如下所示:

class Vertex;
class Polyhedron {
protected:
    std::vector<std::tr1::shared_ptr<Vertex> > m_vertices;
};

并且我已经实现了从 Side 到它的 Vertices 的关联,如下所示:

class Vertex;
class Side {
protected:
    std::vector<std::tr1::weak_ptr<Vertex> > m_vertices;
};

请注意,边的顶点集是多面体顶点集的子集。现在假设我有一个计算一组顶点平均值的函数。该函数当前声明如下:

const Vertex centerOfVertices(std::vector<Vertex*> vertices);

现在,如果我如上所述表示关联,如果我正确理解所有内容,我突然需要两个函数:

const Vertex centerOfVertices(std::vector<std::tr1::shared_ptr<Vertex> > vertices);
const Vertex centerOfVertices(std::vector<std::tr1::weak_ptr<Vertex> > vertices);

因为我无法在 shared_ptr 的向量和weak_ptr 的向量之间进行转换。这对我来说很有趣。我想知道我应该在这里采取什么方法来避免这种情况。

4

3 回答 3

1

但是,我更喜欢使用智能指针在代码中记录关联的所有权语义。

正如你应该的那样。毕竟,这就是他们完美表达的东西。

所以我想将 shared_ptrs 仅用于图中粗箭头表示的关联,而将 weak_ptrs 用于其他所有内容。

去吧,有一个警告:你的所有权看起来不像共享所有权,它是简单的,独特的所有权。因此,这里合适的智能指针不是shared_ptr,而是std::unique_ptr,弱指针将只是原始指针。

现在如果我像上面那样表示关联,我突然需要两个函数……</p>

是的。好吧,或者你使用模板。

或者,由于该函数实际上对共享所有权根本不感兴趣,因此您可以将原始指针传递给它,但这当然意味着首先从您的结构中获取原始指针,这需要客户端添加一个步骤,这可能不会对界面有好处。

于 2012-06-13T13:55:15.303 回答
1

使用共享指针似乎是明智的,尤其是当您发现顶点等可以在多面体之间共享时。

要将弱指针向量转换为共享指针向量,请使用显式构造函数:

centerOfVertices(std::vector<std::tr1::shared_ptr<Vertex> >(vertices.begin(), vertices.end()));
于 2012-06-13T16:02:08.533 回答
0

您当然也可以将 shared_ptr 用于循环引用。在一些罕见的情况下,这实际上是有意义的。但是,一旦你完成了对象,你必须小心打破循环。

于 2012-06-13T14:04:15.983 回答