2011-03-09 85 views
4

我试图避免重新实现我自己笨拙的版本的标准算法,因此正在玩标准库版本。由于我不是C++的专家,因此我谨慎行事,开启全面的调试选项。使用C++标准库算法与valarray

具体而言,我在valarray容器上使用二分查找。下面的代码块似乎产生正确的结果,并且valgrind不会抱怨。尽管如此,我确实感到我处于一个滑坡,因为我不确定我所做的事情是否真的被允许,或者我只是被编译器放出去了。

代表性的一段代码:

#include <iostream> 
#include <valarray> 
#include <algorithm> 
#include <typeinfo> 

using namespace std; 

int main(){ 

valarray<double> v(10); 
for (int i=0 ; i<10 ; ++i){ 
    v[i]=2. *i ; 
    cout<<v[i]<<" "; 
} 
cout << "\n"; 

double what=17; 
double* it=lower_bound(&v[0], &v[10],what) ; 

cout<<it-&v[0]<<" "<<typeid(&v[0]).name()<<" "; 
cout<<typeid(it).name()<<" "<<typeid(it-&v[0]).name()<<"\n"; // ??? 

int idx=it-&v[0]; 
cout<<"v["<<idx<<"]="<<v[idx]<<"\n"; 
} 

问题:

  1. 是我在这里做什么真的合法吗?
  2. 两个指针变为double的区别是什么? (符合???评论)
  3. 类型转换的开销是多少? --- I am与效率有关,因为这种功能将会占用占用90%以上计算时间的代码部分。
+0

我修复了我的答案,不完全错误,我认为它也是完整的。 – Omnifarious 2011-03-09 01:35:49

回答

2
  1. 您使用的int索引到valarray。这个例子是有效的,但不是一般的。使用std::size_t来索引valarray。 (这同样适用于std::vector和普通阵列。)

  2. 于任何类型的两个指针之间的差异是未指定的整数类型的,可能intlong和总是足够小以适合在std::ptrdiff_t

  3. 转换哪个?

+0

哎呀,谢谢!这是我正在使用的特定版本的gcc的功能,还是这是便携式? – 2011-03-09 01:15:44

+0

@振亚:正如我所说(在编辑后),未指定。如果要存储两个指针之间的差异,请始终使用'ptrdiff_t'。 – 2011-03-09 01:19:00

+0

我个人更喜欢使用索引[毕竟它是一个固定大小的数组],但'lower_bound'想要返回一些迭代器。但是,只要它是一个整数类型,我认为它可以安全地用作索引。感谢您的澄清! – 2011-03-09 01:29:34

1

我相信这是所有定义的行为,将继续在任何实现上工作。看看valarray的各种文档,看起来它必须是合法的,才能使::std::valarray的所有其他内容保持正确。在调用resize成员函数或valarray被销毁之前,指向元素的裸指针应保持完全有效。

唯一真正的问题是valarray是否需要连续或不连续地保持其元素。我发现了answer to that question in a post。我会在这里摘录它:

是的,valarray也使用连续的 存储。从 标准的特定措辞($ 26.3.2.3/3):将 表达&一个[I + J] == & A [1] + J 所有的size_t评估为真i和 为size_tĴ使得i + j小于 非常数阵列的长度为 a。

当然,切片仍然不能直接与标准算法一起使用,尽管创建切片迭代器不应该太难。创建一个双向访问迭代器会非常容易,但要难得多(需要很多棘手的数学手段才能完全正确)才能创建一个随机访问迭代器。

两个指针之间的区别变成(如别人所说)::std::ptrdiff_t。这将是不同平台上的不同类型。我使用64位Fedora 14下的gcc,对我来说类型是long。这种“类型转换”没有开销。它甚至不是真正的转换。编译器只是进行减法,就好像两个指针是普通的旧数字一样,结果是某种类型的普通旧数字。这种类型的使用::std::ptrdiff_t是为了确保使用的数字类型足够大,以保持系统中任何两个指针之间的差异。

+0

谢谢!我知道'valarray'在记忆中是连续的[这就是为什么我首先使用];我确实需要随机访问,因为索引很好。正是这个指向整数的对应让我感到困惑。 – 2011-03-09 09:54:31

0

这些it-&v[0]真的吓到我..你的意思是it->v[0]? lower_bound的返回值类型为valarray<double>::iterator,请使用该值代替double*!所有其他解除重复问题将自动消失。例如,您可以执行*itit++,但不能执行it->v[0],因为它不是指针而是迭代器。它很可能是一个导致你所有的企图非法获取其价值的引擎。在迭代器

更多信息:http://www.cppreference.com/wiki/iterator/start

编辑:哦,现在我明白了,你正在使用吓人指针运算!这是如此C,我们不再这样做;)

+1

valarray不支持迭代器。 – 2011-03-09 01:19:04

+0

@ Zhenya valarray支持C++ 11中的迭代器 – 2014-08-30 13:01:38