Ошибка: выражение должно быть модифицируемым lvalue

Я получаю эту ошибку в цикле for, когда пытаюсь присвоить значения x_dev, y_dev и pearson. Насколько я вижу, все они должны быть модифицируемыми. Может ли кто-нибудь увидеть, где я ошибся?

class LoopBody
{  
    double *const x_data;
    double *const y_data;
    double const x_mean;
    double const y_mean;  
    double x_dev;
    double y_dev;
    double pearson; 


public:
    LoopBody(double *x, double *y, double xmean, double ymean, double xdev, double ydev, double pear) 
            : x_data(x), y_data(y), x_mean(xmean), y_mean(ymean), x_dev(xdev), y_dev(ydev), pearson(pear) {}  

    void operator() (const blocked_range<size_t> &r) const {              
        for(size_t i = r.begin(); i != r.end(); i++)
        {
            double x_temp = x_data[i] - x_mean;
            double y_temp = y_data[i] - y_mean;

            x_dev += x_temp * x_temp;
            y_dev += y_temp * y_temp;

            pearson += x_temp * y_temp;

        }
    }
};

Следуя совету @Bathsheba, я преодолел эти проблемы. Однако при запуске parallel_for оператор запускается, но цикл for никогда не вводится.

Здесь я вызываю parallel_for:

parallel_for(blocked_range<size_t>(0,n), LoopBody(x, y, x_mean, y_mean, x_dev, y_dev, pearson), auto_partitioner());

person Ben McAlindin    schedule 11.03.2014    source источник


Ответы (2)


Оператор () помечен const, и вы пытаетесь изменить данные члена класса (например, x_dev, y_dev и person). Это не разрешено, и поэтому вы получаете ошибку времени компиляции.

Возможно, вы захотите удалить const из метода.

В качестве альтернативы вы можете пометить данные членов, которые вы хотите изменить, как mutable, но это не предпочтительное решение, так как это делает код хрупким, трудным для чтения и может нанести ущерб многопоточности.

person Bathsheba    schedule 11.03.2014
comment
Это устраняет эту проблему, но теперь я получаю сообщение об ошибке при компиляции: c:\program files (x86)\tbb41\include\tbb\parallel_for.h(110): ошибка C3848: выражение, имеющее тип 'const LoopBody', потеряет некоторую константу -volatile квалификаторы для вызова 'void LoopBody::operator ()(const tbb::blocked_range‹Value› &)'. Погуглив, это говорит, что исправление будет состоять в том, чтобы включить константу, которую я только что удалил. - person Ben McAlindin; 11.03.2014
comment
Проблема в том, что () не должен изменять данные члена класса. Зачем вам это нужно? Если вам действительно это нужно, то, возможно, создание членов класса mutable и пометка функции const является путем вперед. Но мне это не нравится по причинам, которые я излагаю в ответе. - person Bathsheba; 11.03.2014
comment
Вы абсолютно правы в том, что () не должен модифицировать члены класса, в частности потому, что tbb::parallel_for использует несколько экземпляров тела, и все, что накопилось в одном экземпляре, будет просто потеряно. Таким образом, сочетание const и mutable только скроет настоящую проблему. Правильное решение - использовать tbb::parallel_reduce. - person Alexey Kukanov; 11.03.2014

По-видимому, вы хотите выполнить сокращение, т.е. вычислить некоторые совокупные значения по данным.

Для этого TBB предлагает специальный шаблон функции: parallel_reduce. В отличие от parallel_for, который вы, возможно, используете сейчас, parallel_reduce не требует, чтобы operator() класса тела было константным, потому что экземпляр этого класса накапливает частичные результаты. Однако к классу предъявляются другие требования: необходимость наличия специального конструктора, а также метода для слияния частичных результатов из другого экземпляра тела.

Дополнительную информацию можно найти в руководстве пользователя Intel(R) TBB: http://www.threadingbuildingblocks.org/docs/help/tbb_userguide/parallel_reduce.htm

Также существует перегрузка parallel_reduce, которая принимает два функтора - один для тела и другой для слияния частичных результатов, а также специальное значение "identity", используемое для инициализации аккумуляторов. Но вы одновременно вычисляете три совокупных значения, поэтому вам все равно потребуется структура или класс для хранения всех трех значений в одной переменной.

person Alexey Kukanov    schedule 11.03.2014