处理 C++ 中的惰性计算 类

发布于 2024-07-19 13:47:04 字数 1338 浏览 5 评论 0原文

假设我有一个类:

class NumberCollection
{
public:
    typedef std::set<int> SetType;
    typedef SetType::iterator iterator;
    void insert(int n);

    iterator begin();
    iterator end();
    size_t size() const;

    iterator difficultBegin();
    iterator difficultEnd();
    size_t difficultSize() const;    

private:
    SetType easySet_, difficultSet_;
}

其中 insert() 将一个元素添加到 easySet_difficultSet_ 的成员根据 easySet_ 的成员而变化。

我遇到的问题是,多次插入意味着 difficultSet_ 会不断重新计算。 所以我希望延迟计算 difficultSet_ (即,仅当 difficultBegin()difficultEnd()difficultSize()< /code> 被调用)。 问题是,然后我实际上必须将 difficultSet_ 变成 mutable 因为否则 difficultSize() 无法对其进行操作。

所以现在我的类声明看起来

class NumberCollection
{
public:
    typedef std::set<int> SetType;
    typedef SetType::iterator iterator;
    void insert(int n);

    iterator begin();
    iterator end();
    size_t size() const;

    iterator difficultBegin();
    iterator difficultEnd();
    size_t difficultSize() const;    

private:
    SetType easySet_; 
    mutable SetType difficultSet_;
    mutable bool upToDate_;
}

我觉得这是一个糟糕的设计。 有没有更好的办法?

Let's say I have a class:

class NumberCollection
{
public:
    typedef std::set<int> SetType;
    typedef SetType::iterator iterator;
    void insert(int n);

    iterator begin();
    iterator end();
    size_t size() const;

    iterator difficultBegin();
    iterator difficultEnd();
    size_t difficultSize() const;    

private:
    SetType easySet_, difficultSet_;
}

Where insert() adds an element to easySet_. difficultSet_'s members change depending on the members of easySet_.

The problem I am having is that, multiple insertions means that difficultSet_ is constantly recalculated. So I want difficultSet_ to be calculated lazily (i.e., only when difficultBegin(), difficultEnd(), or difficultSize() are called). The problem is, then I actually have to make difficultSet_ into a mutable because otherwise difficultSize() cannot operate on it.

So now my class declaration looks like

class NumberCollection
{
public:
    typedef std::set<int> SetType;
    typedef SetType::iterator iterator;
    void insert(int n);

    iterator begin();
    iterator end();
    size_t size() const;

    iterator difficultBegin();
    iterator difficultEnd();
    size_t difficultSize() const;    

private:
    SetType easySet_; 
    mutable SetType difficultSet_;
    mutable bool upToDate_;
}

I feel like this is bad design though. Is there a better way?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

鯉魚旗 2024-07-26 13:47:05

这本质上就是 C++ 具有可变结构的原因。 Alan De Smet 关于 mutable 滥用的咆哮展示了以下几种情况:不应该使用可变的。

在这种情况下,hardSize() 不会改变 NumberCollection 所代表的内容 - 这适合标记为 const。 它有时确实需要更改内部结构,这就是为什么您需要将 oddSet_ 和 upToDate_ 标记为可变的。

This is essentially the reason C++ has the mutable construct. Alan De Smet's rant about the misuse of mutable shows the kinds of situations in which mutable should not be used.

In this case, difficultSize() does not change what the NumberCollection represents - which is suitable for marking as const. It does how ever need to change the internals at times, which is why you need to mark difficultSet_ and upToDate_ as mutable.

风启觞 2024-07-26 13:47:05

你的解决方案在 C++98 中很好。 请注意,在 C++11 中,您应该考虑同步对可变数据的访问。 否则,当 STL 使用您的类时,您可能会遇到问题,STL 假定所有 const 成员函数都是线程安全的。

有关更多详细信息,请参阅 const 是否意味着 C+ 中的线程安全+11?

Your solution is fine in C++98. Note that in C++11 you should consider to synchronize the access to your mutable data. Otherwise you may run into problems when you your class is used by the STL, which assumes that all const member functions are thread-safe.

For further details, see Does const mean thread-safe in C++11?

抽个烟儿 2024-07-26 13:47:04

为了帮助理解为什么使用可变,我们可以探索其他选项。

您可以使用const_cast解决同样的问题:

size_t NumberCollection::difficultSize() const
{
     if(!upToDate_)
     {
          NumberCollection& nonConst = const_cast<NumberCollection&>(*this);
          nonConst.difficultSet_ = PerformExpensiveCalculationFunction();
          nonConst.upToDate_ = true;
     }
     // etc....
}

在提供了这个解决方案之后,我会说它不如使用mutable。 如果一个成员被标记为可变,那么只需查看标头,我就可以了解您如何对待它。 如果您使用const_cast,我将无法获得此信息。

但随后有人可能会采取辩论的另一方,并说最好不要在标头中公开实现细节。

To help understand why to use mutable, we can explore other options.

You can solve the same problem using const_cast:

size_t NumberCollection::difficultSize() const
{
     if(!upToDate_)
     {
          NumberCollection& nonConst = const_cast<NumberCollection&>(*this);
          nonConst.difficultSet_ = PerformExpensiveCalculationFunction();
          nonConst.upToDate_ = true;
     }
     // etc....
}

Having offered this solution, I'll say that it's inferior to using mutable. If a member is marked as mutable, then simply by looking at the header I can gather how you are treating it. I don't get this information if you use const_cast.

But then somebody might take the other side of the debate, and say that it's better not to expose implementation details in the header.

好菇凉咱不稀罕他 2024-07-26 13:47:04

这完全就是这样做的方法。 Const 可以表示二进制 const,也可以表示概念上的 const。 使用可变意味着你正在做后者,这很好。

That's totally the way to do it. Const can mean binary const, or it can mean conceptually const. Using mutable means you're doing the later, which is fine.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文