错误:表达式必须是可修改的左值

Posted

技术标签:

【中文标题】错误:表达式必须是可修改的左值【英文标题】:Error: Expression must be a modifiable lvalue 【发布时间】:2014-03-11 11:08:47 【问题描述】:

当我尝试将值分配给 x_dev、y_dev 和 pearson 时,我在 for 循环中出现了这个错误。据我所知,它们都应该是可修改的。谁能看到我哪里出错了?

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());

【问题讨论】:

【参考方案1】:

() 运算符标记为 const,并且您正在尝试修改类成员数据(例如 x_devy_devperson)。这是不允许的,这就是您收到编译时错误的原因。

您可能希望从方法中删除 const

或者,您可以将要修改的成员数据标记为mutable,但这不是首选解决方案,因为它会使代码变脆、难以阅读并且可能对多线程造成严重破坏。

【讨论】:

这解决了这个问题,但我现在在编译时遇到错误:c:\program files (x86)\tbb41\include\tbb\parallel_for.h(110): error C3848: expression has type 'const LoopBody' 将丢失一些 const-volatile 限定符,以便调用 'void LoopBody::operator ()(const tbb::blocked_range &)' 谷歌搜索这表明修复将包括我刚刚删除的 const . 问题是() 不应该修改类成员数据。为什么你需要这样做?如果你真的需要那么,也许,使类成员mutable 并标记函数const 前进的方向。但我不喜欢这样,因为我在答案中陈述了原因。 你是绝对正确的() 不应该修改类成员,特别是因为tbb::parallel_for 使用多个主体实例,并且在单个实例中累积的任何内容都将丢失。因此,constmutable 的组合只会隐藏真正的问题。正确的解决方案是使用tbb::parallel_reduce【参考方案2】:

您似乎想要进行归约,即在数据上计算一些聚合值。

为此,TBB 提供了一个特殊的函数模板:parallel_reduce。与您现在可能使用的 parallel_for 不同,parallel_reduce 不需要主体类的 operator() 为 const,因为该类的实例会累积部分结果。但是,它对类提出了其他要求:需要有一个特殊的构造函数以及一个方法来合并来自另一个 body 实例的部分结果。

更多信息可以在英特尔(R) TBB 用户指南中找到:http://www.threadingbuildingblocks.org/docs/help/tbb_userguide/parallel_reduce.htm

还有parallel_reduce 的重载,它需要两个函子——一个用于主体,另一个用于合并部分结果——以及用于初始化累加器的特殊“身份”值。但是您一次计算三个聚合值,因此您仍然需要有一个结构或类来将所有三个值存储在一个变量中。

【讨论】:

以上是关于错误:表达式必须是可修改的左值的主要内容,如果未能解决你的问题,请参考以下文章

为啥我得到的表达式必须是可修改的左值?

指向函数指针的指针 - 表达式必须是可修改的左值

C++ 表达式必须是可修改的左值

表达式必须是可修改的左值(字符数组)

循环中分配的多维数组说明:表达式必须是可修改的左值

C++的结构体指针中出错:表达式必须是可修改的左值_最后发现解决方法很简单