使用共享指针在 C++ 中对网络建模是否是明智的设计?
Is modelling a Network in C++ with shared pointers a sane design?
我目前正在扩展我的 C++ 知识。为此,我正在编写一个模板网络。 (实际练习是Project Euler's problem 107,如果有人感兴趣的话。)
现在阅读 C++11 中的指针,我的 class 的以下设计看起来很合理:
template< typename T, size_t D >
class Network<T,D>
{
public:
Network();
~Network();
bool add_edge( size_t, size_t, T );
bool remove_edge( size_t, size_t );
struct Node;
struct Edge;
private:
vector<Node> network;
};
初步实现如下
template< typename T, size_t D >
struct Network<T,D>::Edge
{
pair<shared_ptr<Node>,shared_ptr<Node>> vertices;
T weight;
}
template< typename T, size_t D >
struct Network<T,D>::Node
{
Node( size_t idx )
index = idx;
size_t index;
vector<shared_ptr<Edge>> connections;
};
template< typename T, size_t D >
Network<T,D>::Network( )
{
network.reserve( D );
for( size_t s = 0; s <= D; s++ )
network.push_back( Node(s) );
}
template< typename T, size_t D >
Network<T,D>::~Network() {}
请注意,这只是初步代码;我还没有编译任何东西。
但是,出现了以下问题:
- 这是对
std::shared_ptr
的合法使用吗?用它来计算从Edge
s到Node
s的引用可以很容易地确定一个节点是否是孤立的。
在我的模型中,是否可以将 std::shared_ptr
与 std::weak_ptr
交换?
据我了解,没有。在 Edge
中,shared_ptr<Node>
是实际能够计算引用所必需的,在我的 Node
中,shared_ptr<Edge>
是实际保持引用边缘而不丢失它所必需的.
在较小程度上,使用 size_t D
对我的模板有意义吗? (除了将此模型与多 TB 计算机一起用于解决大型网络的可能性很小......)
即使这可能会吸引固执己见的答案,我也愿意设计替代方案。
我会说 shared_ptr
或任何其他智能指针在这里都是错误的工具。因为:
- 节点和边只有一个明确的所有者:邻接矩阵。将节点存储在数组中(就像您现在所做的那样),并将边存储在矩阵中,均按值存储。共享指针在很难建立所有权时很有用(并且是未经过深思熟虑的设计的症状)。
- 将incoming/outgoing条边的个数存储在节点本身,简洁高效
- 构造
shared_ptr
涉及在堆上分配控制块(存储引用计数器和删除器的地方)。 shared_ptr
大小是两个指针的大小。引用计数器维护涉及原子指令,这会在单线程用例中引入不必要的延迟。换句话说,shared_ptr
是可用的最昂贵的指针之一。
我目前正在扩展我的 C++ 知识。为此,我正在编写一个模板网络。 (实际练习是Project Euler's problem 107,如果有人感兴趣的话。)
现在阅读 C++11 中的指针,我的 class 的以下设计看起来很合理:
template< typename T, size_t D >
class Network<T,D>
{
public:
Network();
~Network();
bool add_edge( size_t, size_t, T );
bool remove_edge( size_t, size_t );
struct Node;
struct Edge;
private:
vector<Node> network;
};
初步实现如下
template< typename T, size_t D >
struct Network<T,D>::Edge
{
pair<shared_ptr<Node>,shared_ptr<Node>> vertices;
T weight;
}
template< typename T, size_t D >
struct Network<T,D>::Node
{
Node( size_t idx )
index = idx;
size_t index;
vector<shared_ptr<Edge>> connections;
};
template< typename T, size_t D >
Network<T,D>::Network( )
{
network.reserve( D );
for( size_t s = 0; s <= D; s++ )
network.push_back( Node(s) );
}
template< typename T, size_t D >
Network<T,D>::~Network() {}
请注意,这只是初步代码;我还没有编译任何东西。
但是,出现了以下问题:
- 这是对
std::shared_ptr
的合法使用吗?用它来计算从Edge
s到Node
s的引用可以很容易地确定一个节点是否是孤立的。 在我的模型中,是否可以将
std::shared_ptr
与std::weak_ptr
交换? 据我了解,没有。在Edge
中,shared_ptr<Node>
是实际能够计算引用所必需的,在我的Node
中,shared_ptr<Edge>
是实际保持引用边缘而不丢失它所必需的.在较小程度上,使用
size_t D
对我的模板有意义吗? (除了将此模型与多 TB 计算机一起用于解决大型网络的可能性很小......)即使这可能会吸引固执己见的答案,我也愿意设计替代方案。
我会说 shared_ptr
或任何其他智能指针在这里都是错误的工具。因为:
- 节点和边只有一个明确的所有者:邻接矩阵。将节点存储在数组中(就像您现在所做的那样),并将边存储在矩阵中,均按值存储。共享指针在很难建立所有权时很有用(并且是未经过深思熟虑的设计的症状)。
- 将incoming/outgoing条边的个数存储在节点本身,简洁高效
- 构造
shared_ptr
涉及在堆上分配控制块(存储引用计数器和删除器的地方)。shared_ptr
大小是两个指针的大小。引用计数器维护涉及原子指令,这会在单线程用例中引入不必要的延迟。换句话说,shared_ptr
是可用的最昂贵的指针之一。