valarray::apply()的批判

原创 2005年04月23日 18:30:00

valarray::apply()的批判。

本人因恰好需要对数组做整体+=,-=,max等操作,发现valarray是一个挺好的东西,就用这个东西来帮助操作了。

然后发现了一个看上去更好的valarray::apply():它的描述是——把一个函数f的指针传给apply(),apply()就能返回一个被f作用过于每一个元素的valarray

就是说如果我想把一个数组a的每一个值乘以2得到一个新的数组,那么可以写成:
int f(int i)
{
    return i * 2;
}

valarray<int>a(10);
valarray<int>b(10);

blahblah.../* 把a赋值为 {1,2,3,4,5,6,7,8,9,10}*/

b = a.apply(f); /*于是b就变成 {2,4,6,8,10,12,14,16,18,20}了*/

但是我对整个过程挺拿不准,写了一个constructor,copy constructor, operator = 都带有输出的类来检测,发现运行一次apply()就会调用很多次各种构造器和operator =()。于是打开<valarray>的源代码,发现这个apply()的定义是:

valarray<_Ty> apply(_Ty _F(_Ty)) const
  {_VALOP(_Ty, size(), _F(_Ptr[_I])); }
 
#define _VALOP(TYPE, LENGTH, RHS) /
 valarray<TYPE> _Ans(LENGTH); /
 for (size_t _I = 0; _I < _Ans.size(); ++_I) /
  _Ans[_I] = RHS; /
 return (_Ans)

这样一看,我就认为apply()是一个效率非常低的东西了。因为为了做一个a的每个元素乘2得到的b,它会:
1.产生一个临时valarray: _Ans,长为10。
2.调用f()给_Ans的每一个元素赋值,循环10次。
3.return的时候产生再产生一个用来保存返回值的临时对象,大小也是10,并运行copy constructor将_Ans复制给它
4.再调用operator=()将刚才的临时返回值对象复制给b,循环10次。

其中又:
2.1 在调用f期间,如果f的传参数方式不是传引用,那么每call一次f调用一次copy constructor,在本例中为10次。
    即使是传引用,因为这个引用是const,f中间也必须做一个临时的TYPE对象,还是要产生10次。
2.2 f的返回值必须是传值方式,于是f每返回一次又要生成一个临时返回值对象,调用一次copy constructor.合计10次。
2.3 把f的返回值传给_Ans,要调用TYPE::operator =(),又合计10次。

就是说为了把a全部10个元素每个乘2赋给已经初始化过的b,总计会产生10+10+10+10=40个临时对象,调用operator=()至少20次。再加上销毁对象的操作,额外开销相当大了。显然完全没有用循环来赋值合算。

(我很疑惑为什么apply()不定义成b.apply(f, a)的调用方式,而要写成b = a.apply(f)。如果用前面的方法可以节省中间的_Ans的产生,以及传递_Ans的返回值临时对象的产生。)

另外,apply()的这种形式也限制了不需要传参数与不需要返回值的操作的灵活性。
比如
1.要让a的所有成员赋为一个随机数,虽然可以写一个与传入值无关的f:
int f(int /* not used*/)
{
    return rand();
}
但是写a = a.apply(f)的时候还是有很大浪费。
又如
2.我要输出a里所有的元素,那么定义f:
int f(int i)
{
    cout << i << endl;
    return i;
}
这样可以用a.apply(f)来执行,但是其中多做的返回值处理的操作又浪费了……


综上:我认为valarray::apply()从微观上来看是一个很不好的东东。但是就软件工程的观点来说,它用多余的4倍的损耗节省了开发者写一个循环的精力。所以我写这篇文章纯粹是开发时代的无病呻吟。

gambolgs April 23, 2005

[c++基础]valarray模板详解

还记得vector怎么使用吗?valarray类似vector,也是一个模板类,其主要被用来对一系列元素进行高速的数字计算,其与vector的主要区别在于以下两点 1、valarray定义了一组在两...

C++11系列学习之三----array/valarray

创建数组,是程序设计中必不可少的一环。我们一般可以有以下几种方法来创建数组。 一、C++内置数组 数组大小固定,速度较快 通用格式是:数据类型   数组名[ 数组大小 ]; 如 int a...

STL容器之valarray

valarray,为高速计算设计,以一些简化编程和一般用途的开支做为代价,主要用于数学计算。 valarray被定义于中,sgi将其实现于诸多源文件中。 valarray不是STL标准容器。看起来...

为什么std::valarray那么慢(2)

原创作品,欢迎批评,转载请保留作者信息。 上一篇文章我发现valarray比普通的循环慢了很多,原因在哪里呢? 我们看看valarray是如何实现c=a*b的。 #define _VAL...

varray: 灵活的数组结构与stl valarray的解构(2)

上一片文章我们构造了一个简单的varray类,对这个用户定义的具体类型来说,还不够功能完善,有很多的运算符操作都没有放进去。这是特的为了表述清楚而没有加入的。 这类操作包括: 1。取+/-/~/!...

C++ STL vector, valarray, 和bitSet使用方法对比

三个容器要数vector是最常用的了,但是什么时候应该使用其他容器呢?下面看看他们的用法比较。 初始化: valarray并不是一个标准的stl容器,因为它本身没有iterators,这就是为什么...

js中call与apply用法

前天去面试,有个gg问了一些js知识,其中有一道call与apply用法的题目,尽管在365天前用过call方法,但当时还是没能答上来,今天深入总结一下call和apply,它们的作用都是将函数绑定到...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:valarray::apply()的批判
举报原因:
原因补充:

(最多只允许输入30个字)