图表可以表示为邻接矩阵或邻接列表。我的Graph
对象将图形表示为邻接矩阵。出于性能原因,除非有要求,否则我不会计算邻接表;但是,一旦提出要求,我想保留清单(以避免重新建立)。
是否适合制作邻接列表mutable
,以便用户可以为其他const
Graph
个对象生成邻接列表?我问,因为我不相信构建邻接矩阵会被视为“物理”而不是Graph
状态的“逻辑”变化。我也有adjacencyListBuilt
方法,因此邻接列表的构建不是“不可见的”(参见https://isocpp.org/wiki/faq/const-correctness#mutable-data-members)。
如果我理解正确,声明adjacencyList
实例变量mutable
将允许任何方法更新它。有没有办法只有buildAdjacencyList
方法能够修改adjacencyList
对象上的const
实例变量?
答案 0 :(得分:7)
使用mutable
缓存从内部成员计算的结果是合适的。请注意,它可能会破坏线程的安全性。
但我也会考虑在const
对象上执行计算的单独的类或函数。
答案 1 :(得分:2)
是否有一种方法只允许buildAdjacencyList方法修改const对象上的adjacencyList实例变量?
当然,使用嵌套的私有成员和friend
:
class myGraph;
void buildAdjacencyListImpl(const myGraph&);
class myGraph
{
class myAdjacencyListCache
{
mutable realAdjacencyList cached_list;
friend void buildAdjacencyListImpl(const myGraph&);
} adj_list;
friend void buildAdjacencyListImpl(const myGraph&);
void buildAdjacencyList() const { buildAdjacencyListImpl(*this); }
};
void buildAdjacencyListImpl( const myGraph& g )
{
realAdjacencyList& listToBuild = g.adj_list.list_cache;
// it isn't const, and can be modified
}
答案 2 :(得分:1)
“即时计算”正是mutable
所发明的,因此是的,它是一个合适的用途。请注意,接口不会特别请求构建它;你只是要求访问,并且该类会注意到它尚未构建,并在“幕后”构建它。因此,逻辑状态不会受到影响。
如果您正在考虑一个函数来请求构建,然后是一个函数或一组访问函数,在尚未请求构建时调用将无效,那么您做错了。请注意,问题将出现在接口而不是实现上;因此,无论您是否使用mutable
实现它都是错误的。
关于如何进一步保护它免受其他方法影响的问题:如果我理解正确,那么邻接列表中只应该做两件事:它应该从当前的邻接矩阵计算,或者它应该是无效的。因此,我建议将其封装到一个单独的类(私有到Graph
类)中,该类封装了可变成员(并且本身用作非可变成员变量),并且只提供两个操作:(1)访问关联矩阵(const函数,计算列表,如果尚未计算)和(2)使列表无效(非const,因为只有对图的更改才能使列表无效)。这样,Graph
类的const成员函数都不能修改列表。
答案 3 :(得分:1)
事实证明,在我的特定情况下,有太多不同的缓存值使得事物变得非常快。 (上面的描述被简化了。)相反,我决定制作两个不同版本的Graph
:ImmutableGraph
和MutableGraph
。 ImmutableGraph
没有添加或删除边和顶点的方法;因此,很少有ImmutableGraph
应声明const
的情况。