如何重写在D中使用mutable的C ++代码?

时间:2011-12-30 05:36:39

标签: class-design d mutable

如果你需要在D中重写以下C ++代码,你会怎么做?

struct A{

    const S* _s;
    B _b;
    C _c;
    mutable C _c1, _c2;

    A(const B& b, const C& c, const S* s){ /*...*/ }

    void compute(const R& r) const
    {
      //...
      _c1 = ...
      _c2 = ...
    }
};

D没有mutable,根据我的经验,它很少用于C ++。但是,假设mutable在正确的原因使用{D =

},我有什么选择?

3 个答案:

答案 0 :(得分:6)

D'immutable是传递性的,当给定不可变引用(例如不可变成员函数中的this引用)时,所有字段也是不可变的。 D. const只存在于D中以存在绑定可变和不可变数据,但由于immutable可以隐式转换为const,因此它也必须是可传递的。一旦你进入不可变(或const),你就不能回去了。

好处有几个:不可变数据可以安全地在线程之间共享,如果需要可以放在ROM中,并且很容易推理。

D中没有逻辑const的余地,无论好坏。

答案 1 :(得分:4)

短版;你不能,按设计。

更长的版本,D的设计者(在一些史诗般的辩论之后)总结说,可变的好处被缺点所抵消。 (参见:jA_cOp对某些细节的回答,许多其他的反应都是由于制作并发编程的意图以及那些不那么难看的推理。)

答案 2 :(得分:3)

您有三种方法可以解决这个问题:

  1. 抛弃const。这会使编译器起作用,但无法保证您的代码能够按预期工作。特别是,如果你从多个线程在同一个对象上调用该函数,那么你将受到数据竞争的支配。

  2. 使用外部数据结构存储可变对象:

    struct A
    {
        static C[const(A)*] _c1s, _c2s;
    
        void compute(ref const(R) r) const
        {
            _c1s[&this] = ...
            _c2s[&this] = ...
        }
    }
    

    我正在使用&this作为外部哈希表的键,但您可能最好使用某种唯一ID。这是一个非常丑陋和棘手的解决方案。我不喜欢它。另请注意,哈希表是线程本地的,因此同一对象在不同的​​线程上将具有不同的值。这可能适用于您的特定应用,也可能不适用。

  3. 重新思考如何在D中使用const

    在D中,const是传递和按位的,即不支持逻辑const。这样做的目的是保证不会出现并发共享数据写入。即使你的代码可能逻辑const 正确,如果两个线程试图在同一个对象上调用compute,它仍然会中断,所以D不允许它并且不提供合法的转义(no {{ 1}})。

    基本上,只有在按位const 时,才应将函数标记为mutable

    这样做的结果是你应该在D中使用const比在C ++中少得多,因为你需要比你需要逻辑const少得多的按位常量。

    作为一个例子,考虑一个简单的(无意义的)通用const函数,它告诉你两个对象是否相等:

    equal

    请注意,我没有将函数参数标记为bool equal(T)(T lhs, T rhs) { return lhs == rhs; } 。这是故意的。测试相等性不应该要求按位const - 它只需要逻辑const,因此在对象上强制执行D的const级别将是不必要的限制。

    正如jA_cOp所说,D社区在D中看不到逻辑const的余地,无论好坏。当你试图像C ++的const一样使用D的const时会出现问题。它们不一样,所以不要以同样的方式使用它们!如果函数可能需要使用逻辑const,那么就不要将它们标记为按位const!