используя стандартные библиотечные алгоритмы c ++ с valarray - PullRequest
4 голосов
/ 09 марта 2011

Я стараюсь не реализовывать свои собственные неуклюжие версии стандартных алгоритмов и, таким образом, играю со стандартными версиями библиотеки. Поскольку я не эксперт в 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";
}

Вопросы:

  1. То, что я здесь делаю, действительно законно?
  2. Как получается, что разница между двумя указателями на удвоение становится int? (в соответствии с комментарием ???)
  3. Каковы издержки при преобразовании типов? --- Я * обеспокоен эффективностью, так как такого рода функциональность собирается в той части кода, которая занимает более 90% времени вычислений.

Ответы [ 3 ]

2 голосов
/ 09 марта 2011
  1. Вы используете int для индексации в valarray.Это верно для примера, но не в целом.Используйте std::size_t для индексации в valarray.(То же самое относится к std::vector и обычным массивам.)

  2. Разница между двумя указателями на любой тип имеет неопределенный целочисленный тип, вероятно int или long и всегдадостаточно мал, чтобы поместиться в std::ptrdiff_t.

  3. Какое преобразование?

1 голос
/ 09 марта 2011

Я считаю, что все это определенное поведение, которое будет продолжать работать в любой реализации.Глядя на различную документацию для valarray, кажется, что она должна быть законной, чтобы все остальное в ::std::valarray оставалось верным.Обнаженные указатели на элементы должны оставаться в силе до тех пор, пока не будет вызвана функция-член resize или пока не будет уничтожено valarray.

Единственный реальный вопрос заключается в том, требуется ли valarray для хранения его элементов.смежно или нет.И я нашел ответ на этот вопрос в сообщении .Я приведу его здесь:

Да, valarray также использует непрерывное хранилище.Специальная формулировка из стандарта ($ 26.3.2.3 / 3): выражение & a [i + j] == & a [i] + j оценивается как истинное для всех size_t i и size_t j, так что i + j меньше, чемдлина неконстантного массива a.

Конечно, срезы по-прежнему нельзя использовать напрямую со стандартными алгоритмами, хотя создание итератора срезов не должно быть слишком сложным.Было бы довольно легко сделать двунаправленный, но гораздо сложнее (сложная математика, которую вы должны правильно понять) создать итератор произвольного доступа.

Разница между двумя указателями становится (как у кого-то еще)сказал) ::std::ptrdiff_t.Это будет другой тип на разных платформах.Я использую gcc под 64-битной Fedora 14, и тип для меня long.В этом «преобразовании типов» нет накладных расходов.Это даже не обращение на самом деле.Компилятор просто выполняет вычитание, как если бы два указателя были обычными старыми числами, а результат - простым старым числом некоторого типа.* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Т по типу * * * * * * * * * * * * * * * * * * * * * * * * * Использовать для этого типа ::std::ptrdiff_t, чтобы убедиться, что используемый тип числа достаточно большой, чтобы удерживать разницу между любыми двумя указателями в системе.

0 голосов
/ 09 марта 2011

Эти it-&v[0] действительно пугают меня .. Вы имели в виду it->v[0]?Возвращаемое значение lower_bound имеет тип valarray<double>::iterator, используйте его вместо double*!Все другие проблемы разыменования исчезнут автоматически.Например, вы можете сделать *it и it++, но вы не можете сделать it->v[0], потому что это не указатель, а итератор.Это вполне может быть v.end() -тератор, заставляющий всех ваших посетителей признать его значение незаконным.

Подробнее об итераторах: http://www.cppreference.com/wiki/iterator/start

Редактировать: О, теперь я вижу, выиспользуя страшную арифметику указателя!Это оооочень С, мы больше этого не делаем;)

...