C++ 数组将其元素分开

C++ 数组将其元素分开,c++,c++11,valarray,C++,C++11,Valarray,当我将valarray除以它的第一个元素时,只有第一个元素变为1,其他元素保持其原始值 #include <iostream> #include <valarray> using namespace std; int main() { valarray<double> arr({5,10,15,20,25}); arr=arr/arr[0]; // or arr/=arr[0]; for(int value:arr)cout <

当我将valarray除以它的第一个元素时,只有第一个元素变为1,其他元素保持其原始值

#include <iostream>
#include <valarray>
using namespace std;

int main() {
    valarray<double> arr({5,10,15,20,25});
    arr=arr/arr[0]; // or arr/=arr[0];

    for(int value:arr)cout << value << ' ';
    return 0;
}
预期产出为:

1 10 15 20 25
1 2 3 4 5
为什么实际产出不如预期

我将g++(4.8.1)与-std=c++11一起使用,这一个可以工作:

#include <iostream>
#include <valarray>
using namespace std;

int main() {
    valarray<double> arr({5,10,15,20,25});
    auto v = arr[0];
    arr=arr/v; // or arr/=arr[0];

    for(int value:arr)cout << value << ' ';
    return 0;
}
#包括
#包括
使用名称空间std;
int main(){
valarray arr({5,10,15,20,25});
自动v=arr[0];
arr=arr/v;//或arr/=arr[0];

对于(int-value:arr)cout,发生这种情况的详细原因是由于
valarray
中使用了一些实现技巧来提高性能。libstdc++和libc++都使用
valarray
操作的结果,而不是立即执行操作。这是[valarray.syn]明确允许的C++标准中的P3:

任何返回
valarray
的函数都可以返回另一种类型的对象,只要
valarray
的常量成员函数也适用于此类型

在您的示例中发生的情况是,
arr/arr[0]
不会立即执行除法,而是返回一个类似
\u Expr
的对象,该对象引用了
arr
arr[0]
。将该对象分配给另一个
valarray
时,将执行除法操作,并将结果直接存储到分配的左侧(这避免了创建临时
valarray
来存储结果,然后将其复制到左侧)

因为在您的示例中,左侧是同一个对象,
arr
,这意味着一旦使用结果更新了
arr
中的第一个元素,表达式模板中存储的对
arr[0]
的引用就引用了不同的值

换句话说,最终结果是这样的:

valarray<double> arr{5, 10, 15, 20, 25};
struct DivisionExpr {
  const std::valarray<double>& lhs;
  const double& rhs;
};
DivisionExpr divexpr = { arr, arr[0] };
for (int i = 0; i < size(); ++i)
  arr[i] = divexpr.lhs[i] / divexpr.rhs;
valarray arr{5,10,15,20,25};
结构分区表达式{
常数标准::valarray和lhs;
康斯特酒店;
};
DivisionExpr DivisionExpr={arr,arr[0]};
对于(int i=0;i
for循环的第一次迭代将
arr[0]
设置为
arr[0]/arr[0]
,即
arr[0]=1
,然后所有后续迭代将设置
arr[i]=arr[i]/1
,这意味着值不会改变


我正在考虑更改libstdc++实现,这样表达式模板将直接存储一个
double
,而不是保存一个引用。这意味着
arr[I]/divexpr.rhs
将始终计算
arr[I]/5
,而不使用
arr[I]的更新值

我知道我可以做到这一点,但我想知道为什么arr/=arr[0]不能做到work@appleapple我已经在答案中写了它。我强烈怀疑它依赖于实现,但直觉上,如果我真的要求开发这种方法,我就会这样做。在
arr=arr/arr[0]
isnotfirst
arr/arr[0]
求值,然后将结果分配给
arr
?@tobi303请参见:对数值数组中的每个元素应用复合赋值运算符。由于
arr[0]
是通过引用返回的,因此其余部分如回答中所述。with
arr.operator=(arr.operator/(arr[0]);
不是第一个
arr.operator/(arr[0])
计算,然后将结果传递给
操作符=
?似乎
操作符/
使用了对
arr[0]
@tobi303的引用。我认为您是对的,操作符[]返回对arr[0]的引用参考资料直接传递给操作员/。谢谢you@tobi303你介意发布一个答案吗?我想你的评论正是我想要的。如果我能理解的话,我会的,但是
操作符/
有签名
模板std::valarray操作符/(const std::valarray&lhs,const std::valarray&rhs);
(注意const)因此,不应修改输入,而应创建一个临时文件来存储其结果(在返回结果之前)。也许这是一些
valarray
魔法…你真的对
/
/=
有同样的感觉吗?现在我很好奇,一旦我有时间,我会把它作为实现操作符的练习,然后也许我会得到它。标准也(明确地)有吗当rhs是表达式模板时,允许执行
操作符=
?这就是使用表达式模板的目的,以避免创建任何临时数组来存储结果。您想解释一下吗?这太奇怪了…我刚刚尝试了
arr=arr/arr[0]+arr
,它给了我
611172329
!(如果我有新问题,请告诉我。谢谢)解释是一样的:对某些操作的求值会延迟,并在稍后执行。您在赋值表达式的两侧以及在单个算术表达式中的多个位置使用它,这是在误用
valarray
。这使编译器关于
valarray
操作数不别名eac的假设无效是的,完全一样。我可能觉得不够。谢谢。