如果你需要在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没有可变性,根据我的经验,它很少用于C语言.但是,假设在这里使用mutable是正确的原因,我在D中的选择是什么?
解决方法
您有三种方法可以解决这个问题:
>抛弃常数.这会使编译器起作用,但无法保证您的代码能够按预期工作.特别是,如果从多个线程在同一个对象上调用该函数,那么您将受到数据竞争的支配.
>使用外部数据结构来存储可变对象:
struct A { static C[const(A)*] _c1s,_c2s; void compute(ref const(R) r) const { _c1s[&this] = ... _c2s[&this] = ... } }
我正在使用& this作为外部哈希表的关键,但你可能最好使用某种独特的ID.这是一个非常丑陋和棘手的解决方案.我不喜欢它.另请注意,哈希表是线程本地的,因此同一对象在不同的线程上将具有不同的值.这可能适用于您的特定应用,也可能不适用.
>重新思考如何在D中使用const
在D中,const是传递的和按位的,即不支持逻辑const.这样做的目的是保证不会出现并发共享数据写入.尽管你的代码在逻辑上可能是正确的,但如果两个线程试图在同一个对象上调用compute,它仍然会中断,因此D不允许它并且不提供合法的转义(不可变).
实质上,只有当它们是按位const时才应将函数标记为const.
结果是你应该在D中使用const比在C中少得多,因为你需要比你需要逻辑const少得多的按位const.
举个例子,考虑一个简单的(无意义的)泛型相等函数,告诉你两个对象是否相等:
bool equal(T)(T lhs,T rhs) { return lhs == rhs; }
请注意,我没有将函数参数标记为const.这是故意的.对相等性的测试不应该要求按位const – 它只需要逻辑const,因此在对象上强制执行D的const级别将是不必要的限制.
正如jA_cOp所说,D社区在D中看不到逻辑const的余地,无论好坏.当你尝试像C的const一样使用D的const时会出现问题.它们不一样,所以不要以同样的方式使用它们!如果函数可能需要使用逻辑const,那么就不要将它们标记为按位const!