“实时计算”是否适用于可变?

时间:2017-01-01 17:36:22

标签: c++ mutable const-correctness

图表可以表示为邻接矩阵或邻接列表。我的Graph对象将图形表示为邻接矩阵。出于性能原因,除非有要求,否则我不会计算邻接表;但是,一旦提出要求,我想保留清单(以避免重新建立)。

是否适合制作邻接列表mutable,以便用户可以为其他const Graph个对象生成邻接列表?我问,因为我不相信构建邻接矩阵会被视为“物理”而不是Graph状态的“逻辑”变化。我也有adjacencyListBuilt方法,因此邻接列表的构建不是“不可见的”(参见https://isocpp.org/wiki/faq/const-correctness#mutable-data-members)。

如果我理解正确,声明adjacencyList实例变量mutable将允许任何方法更新它。有没有办法只有buildAdjacencyList方法能够修改adjacencyList对象上的const实例变量?

4 个答案:

答案 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)

事实证明,在我的特定情况下,有太多不同的缓存值使得事物变得非常快。 (上面的描述被简化了。)相反,我决定制作两个不同版本的GraphImmutableGraphMutableGraphImmutableGraph没有添加或删除边和顶点的方法;因此,很少有ImmutableGraph应声明const的情况。