Как переписать код C ++, который использует mutable в D? - PullRequest
6 голосов
/ 30 декабря 2011

Если вам нужно переписать следующий код C ++ на D, как бы вы это сделали?

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 ]

6 голосов
/ 30 декабря 2011

D immutable является транзитивным, когда ему дается неизменяемая ссылка (например, ссылка this в неизменяемой функции-члене), все поля также являются неизменяемыми. В D. нет никакого способа обойти это. const существует только в D для связывания изменяемых и неизменяемых данных, но поскольку неизменяемый неявно преобразуется в const, он также должен быть транзитивным. Как только вы станете неизменным (или постоянным), вы не сможете вернуться назад.

Преимущества несколько: неизменные данные можно безопасно распределять между потоками, при желании их можно поместить в ПЗУ, и их легко аргументировать.

Просто нет места для логического констант в D, к лучшему или к худшему.

4 голосов
/ 30 декабря 2011

короткая версия;Вы не можете, по замыслу.

Более длинной версии, разработчики D пришли к выводу (после некоторых эпических дебатов), что преимущества mutable перевешиваются недостатками.(См. Ответ jA_cOp для некоторых деталей, многие другие причины вызваны намерением сделать параллельное программирование и рассуждения там менее уродливыми.)

3 голосов
/ 30 декабря 2011

У вас есть три варианта решения этой проблемы:

  1. Отбросьте const. Это испортит компилятор, но нет гарантии, что ваш код будет работать так, как задумано. В частности, если вы вызываете эту функцию для одного и того же объекта из нескольких потоков, тогда вы находитесь в зависимости от гонок данных.

  2. Использование внешней структуры данных для хранения изменяемых объектов:

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

    Я использую &this в качестве ключа для внешней хеш-таблицы, но вам, вероятно, будет лучше использовать какой-то уникальный идентификатор. Это очень уродливое и хитрое решение. Мне это не нравится Также обратите внимание, что хеш-таблицы являются локальными для потоков, поэтому один и тот же объект будет иметь разные значения в разных потоках. Это может или не может быть желательным для вашего конкретного применения.

  3. Переосмыслите, как вы используете const в D.

    В D const является транзитивным и побитовым, то есть логическая константа не поддерживается. Цель этого состоит в том, чтобы гарантировать одновременную совместную запись данных. Даже если ваш код может быть логически постоянным правильным, он все равно прервется, если два потока попытались вызвать compute для одного и того же объекта, поэтому D запрещает его и не обеспечивает законного выхода (нет mutable).

    По сути, вы должны помечать функции как const только тогда, когда они поразрядно постоянны .

    В результате вы должны использовать const в D намного меньше, чем в C ++, потому что вам требуется побитовое const намного меньше, чем логическое.

    В качестве примера рассмотрим простую (бессмысленную) обобщенную функцию equal, которая сообщает, равны ли два объекта:

    bool equal(T)(T lhs, T rhs) { return lhs == rhs; }
    

    Обратите внимание, что я не пометил параметры функции как const. Это специально. Тестирование на равенство не должно требовать побитового const - оно требует только логического const, поэтому принудительное использование уровня const для D будет бесполезным ограничением.

    Как говорит jA_cOp, сообщество D не видит места для логического констант в D, к лучшему или к худшему. Проблема возникает, когда вы пытаетесь использовать D const, как C ++. Они не одинаковы, поэтому не используйте их одинаково! Если есть какая-либо вероятность того, что функция может потребовать использования логического const, не помечайте их как побитовые const!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...