我试图避免重新实现我自己的标准算法的笨拙版本,因此我正在使用标准库版本。由于我不是C ++方面的专家,所以我会谨慎行事并打开完整的调试选项。
具体来说,我在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";
}
问题:
???
评论的行中)答案 0 :(得分:2)
您正在使用int
索引valarray
。这对于这个例子是有效的,但不是一般的。使用std::size_t
索引valarray
。 (std::vector
和普通数组也是如此。)
指向任何类型的两个指针之间的区别是未指定的整数类型,可能是int
或long
,并且总是足够小以适合std::ptrdiff_t
。
哪种转换?
答案 1 :(得分:1)
我相信这是所有定义的行为,将继续适用于任何实现。查看valarray的各种文档,看起来它必须合法才能使::std::valarray
的所有其他内容成立。在调用resize
成员函数或销毁valarray
之前,指向元素的裸指针应保持完全有效。
唯一真正的问题是,valarray
是否需要连续保持其元素。我找到了answer to that question in a post。我会在这里摘录它:
是的,valarray也使用连续的 存储。具体措辞来自 标准是($ 26.3.2.3 / 3): 表达&amp; a [i + j] ==&amp; a [i] + j 对于所有size_t我评估为真 size_t j使得i + j小于 非常数数组的长度 一个。
当然,切片仍然无法直接与标准算法一起使用,尽管创建切片迭代器不应该太难。制作一个双向的很容易,但要创建一个随机访问迭代器要困难得多(要完全正确地进行大量的数学操作)。
两个指针之间的区别变成(正如其他人所说)::std::ptrdiff_t
。这将是不同平台上的不同类型。我在64位Fedora 14下使用gcc,类型为long
。这种'类型转换'没有开销。它甚至不是转换。编译器只进行减法,好像两个指针是普通的旧数字,结果是某个类型的普通旧数字。使用::std::ptrdiff_t
作为类型是为了确保所使用的数字类型足够大,以保持系统中任何两个指针之间的差异。
答案 2 :(得分:0)
这些it-&v[0]
真的吓到我..你的意思是it->v[0]
? lower_bound的返回值是valarray<double>::iterator
类型,请使用它而不是double*
!所有其他derefencing问题将自动消失。例如,您可以执行*it
和it++
但不能执行it->v[0]
,因为它不是指针而是迭代器。它很可能是一个v.end()
- 迭代器,使你的所有注意力都变得非法。
有关迭代器的更多信息:http://www.cppreference.com/wiki/iterator/start
编辑:哦,现在我明白了,你正在使用可怕的指针运算!那就是C,我们不再这样做了;)