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

Arl*_*len 6 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 = ...
    }
};
Run Code Online (Sandbox Code Playgroud)

D没有mutable,而且根据我的经验,它很少用于C++.但是,假设mutable在这里使用正确的原因,我在D中的选择是什么?

jA_*_*cOp 6

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

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

D中的逻辑常量根本没有空间,无论好坏.


Pet*_*der 3

您有三种选择来处理这个问题:

  1. 抛弃了const。这会让编译器崩溃,但不能保证你的代码会按预期工作。特别是,如果您从多个线程在同一个对象上调用该函数,那么您就会受到数据竞争的影响。

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

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

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

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

    在 D 中,const是传递且按位的,即不支持逻辑常量。这样做的目的是保证防止并发共享数据写入。即使您的代码在逻辑上可能是 const正确的,但如果两个线程尝试调用compute同一个对象,它仍然会中断,因此 D 不允许它并且不提供合法的转义( no mutable)。

    本质上,您应该const仅将函数标记为按位 const

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

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

    bool equal(T)(T lhs, T rhs) { return lhs == rhs; }
    
    Run Code Online (Sandbox Code Playgroud)

    请注意,我没有将函数参数标记为const。这是故意的。相等性测试不应该要求按位 const —— 它只需要逻辑 const,因此在对象上强制执行 D 的 const 级别将是不必要的限制。

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