当我将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
答案 0 :(得分:3)
这个有效:
#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;
}
问题是您尝试使用同时修改的数组(arr[0]
)中的值(arr
)。
直观地说,一旦您通过arr[0]
更新arr[0]/arr[0]
,它包含什么价值?
那么,这就是从现在开始用来划分其他价值的价值......
请注意,同样适用于arr/=arr[0]
(首先,arr[0]/arr[0]
发生,而不是所有其他的,在for循环中或类似的东西)。
另请注意documentation operator[]
std::valarray
的{{1}}会返回T&
。这证实了上面的假设:它作为迭代的第一步转向1
,然后所有其他操作都无用。
通过简单地复制它就可以解决问题,如示例代码中所示。
答案 1 :(得分:1)
发生这种情况的详细原因是valarray
中用于提高性能的实现技巧。 libstdc ++和libc ++都使用expression templates作为valarray
操作的结果,而不是立即执行操作。 [valarray.syn] p3在C ++标准中明确允许这样做:
任何返回
valarray<T>
的函数都被允许返回另一种类型的对象,只要提供了所有valarray<T>
的const成员函数也适用于此类型。
您的示例中发生的事情是arr/arr[0]
没有立即执行除法,而是返回_Expr<__divide, _Valarray, _Constant, valarray<double>, double>
之类的对象,该对象引用arr
和引用到arr[0]
。当该对象被分配给另一个valarray
时,执行除法运算并将结果直接存储到赋值的左侧(这样可以避免创建临时valarray
来存储结果然后复制它进入左侧)。
因为在您的示例中,左侧是同一个对象arr
,这意味着一旦arr[0]
中的第一个元素,对表达式模板中存储的arr
的引用就会引用不同的值{1}}已更新结果。
换句话说,最终结果是这样的:
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;
for循环的第一次迭代会将arr[0]
设置为arr[0] / arr[0]
,即arr[0] = 1
,然后所有后续迭代都将设置为arr[i] = arr[i] / 1
,这意味着值为“{1}} ;改变。
我正在考虑更改libstdc ++实现,以便表达式模板直接存储double
而不是保存引用。这意味着arr[i] / divexpr.rhs
始终会评估arr[i] / 5
,而不会使用arr[i]
的更新值。