crash when using upper_bound in C++ - c++

I have following program which crashed at upper bound call. I am not getting why there is a crash. Any reason why I am having a crash. Thanks for your help and time.
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
enum quality { good = 0, bad, uncertain };
struct sValue {
int time;
int value;
int qual;
};
struct CompareLowerBoundValueAndTime {
bool operator()( const sValue& v, int time ) const {
return v.time < time;
}
bool operator()( const sValue& v1, const sValue& v2 ) const {
return v1.time < v2.time;
}
bool operator()( int time1, int time2 ) const {
return time1 < time2;
}
bool operator()( int time, const sValue& v ) const {
return time < v.time;
}
};
struct CompareUpperBoundValueAndTime {
bool operator()( const sValue& v, int time ) const {
return v.time > time;
}
bool operator()( const sValue& v1, const sValue& v2 ) const {
return v1.time > v2.time;
}
bool operator()( int time1, int time2 ) const {
return time1 > time2;
}
bool operator()( int time, const sValue& v ) const {
return time > v.time;
}
};
class MyClass {
public:
MyClass() {
InsertValues();
}
void InsertValues();
int GetLocationForTime(int time);
void PrintValueContainer();
private:
vector<sValue> valueContainer;
};
void MyClass::InsertValues() {
for(int num = 0; num < 5; num++) {
sValue temp;
temp.time = num;
temp.value = num+1;
temp.qual = num % 2;
valueContainer.push_back(temp);
}
}
void MyClass::PrintValueContainer()
{
for(int i = 0; i < valueContainer.size(); i++) {
std::cout << i << ". " << valueContainer[i].time << std::endl;
}
}
int MyClass::GetLocationForTime(int time)
{
std::vector< sValue >::iterator lower, upper;
lower = std::lower_bound(valueContainer.begin(), valueContainer.end(), time, CompareLowerBoundValueAndTime() );
upper = std::upper_bound(valueContainer.begin(), valueContainer.end(), time, CompareUpperBoundValueAndTime() ); // Crashing here.
std::cout << "Lower bound: " << lower - valueContainer.begin() << std::endl;
std::cout << "Upper bound: " << upper - valueContainer.begin() << std::endl;
return lower - valueContainer.begin();
}
int main()
{
MyClass a;
a.PrintValueContainer();
std::cout << "Location received for 2: " << a.GetLocationForTime(2) << std::endl;
return 0;
}

lower_bound and upper_bound work on a sorted sequence. The sequence has to be sorted using the same comparing function that you pass to both functions.
When you insert the elements in InsertValues you insert them in ascending order, so your CompareLowerBoundValueAndTime is a correct way to compare them.
But for upper_bound you're passing a different compare function. Pass CompareLowerBoundValueAndTime() and it should work.
Note that CompareLowerBoundValueAndTime is a misleading name. It should be something along the lines of CompareValueAndTimeAscending.

You should use the same comparer for both upper_bound and lower_bound. The difference is in the algorithm, not in the comparison.

Your compiler is giving you the answer. Check your code here: http://ideone.com/x6RE9
This gives you an error saying:
prog.cpp: In member function ‘int MyClass::GetLocationForTime(int)’:
prog.cpp:94: error: no match for ‘operator*’ in ‘*upper.__gnu_cxx::__normal_iterator<_Iterator, _Container>::operator* [with _Iterator = sValue*, _Container = std::vector<sValue, std::allocator<sValue> >]()’
You don't have to dereference upper twice, it doesn't make any sense.

I think you are getting an assertion error in upper_bound because it is finding that your sequence is not correctly sorted.
You seem to misunderstand what upper_bound does. It is the same as lower_bound except that the item pointed to by the iterator will be strictly greater than the search value, not greater-or-equal. IF there are no such values, it will point to the end of the sequence.
When using a predicate (Pred), it needs to be sorted such that
Pred( iter2, iter1 )
will return false whenever iter2 appears later than iter1 in the sequence.
That is not the case with your sequence and predicate combination, therefore you are getting an assertion error.

Related

std::map<struct,struct>::find is not finding a match, but if i loop thru begin() to end() i see the match right there

struct chainout {
LONG cl;
std::string cs;
bool operator<(const chainout&o)const {
return cl < o.cl || cs < o.cs;
}
} ;
struct chainin{
std::string tm;
std::string tdi;
short mss;
LONG pinid;
bool operator<(const chainin&o)const {
return mss < o.mss || pinid < o.pinid || tm<o.tm; //no tdi right now it's always empty
}
};
std::map <chainin,chainout> chainmap;
std::map<chainin,chainout>::iterator it;
chainin ci;
chainout co;
string FADEDevicePinInfo::getNetAtPinIdTmTidMss (const LONG p,const string tm, const string tid,const LONG mss){
ci.tm=tm;
// ci.tdi=tid;
ci.tdi="";
ci.mss=(short)mss;
ci.pinid=p;
for (it=chainmap.begin();it!=chainmap.end();it++){
if(it->first.pinid==ci.pinid && it->first.tm==ci.tm&&it->first.mss==ci.mss && it->first.tdi==ci.tdi){
cout << "BDEBUG: found p["; cout<<it->first.pinid; cout<<"] tm["; cout<<it->first.tm.c_str();cout<<"] mss[";cout<<it->first.mss;cout<<"] : ";cout<<it->second.chainSignal.c_str();cout<<endl;
}
}
it=chainmap.find(ci);
if(it == chainmap.end()){
MSG(SEV_T,("no pin data found for pin[%ld]/tm[%s]/tdi[%s]/mss[%ld]",ci.pinid,ci.tm.c_str(),ci.tdi.c_str(),ci.mss));
}
return it->second.cs;
}
This is both printing the successfully found line, and then throwing the sev_t error due to map::find not returning a match. what did i do wrong?
I added print statements thruout the < function, but it seems to be ordering the map correctly, and when i do the lookup, it seems to find the correct mss/pinid, but then only sees one tm, which is the wrong tm.
As noted in comments, you have a bad comparison operator. If you don't know what order the objects should be sorted in, then neither does std::map or any other sorted container.
When you have multiple things to compare, consider deciding which is most important, and use std::tie to compare them, as demonstrated here:
#include <string>
#include <iostream>
struct chainout {
int cl;
std::string cs;
bool operator<(const chainout&o)const {
return std::tie(cl, cs) < std::tie(o.cl, o.cs);
}
};
int main(){
chainout a{ 1, "b" };
chainout b{ 2, "a" };
std::cout << (a < b) << std::endl;
std::cout << (b < a) << std::endl;
}
The operator< for both of your structs are implemented incorrectly.
std::map requires key comparisons to use Strict Weak Ordering. That means when your structs want to compare multiple fields, they need to compare later fields only when earlier fields compare equal. But you are not checking for that condition. You are returning true if any field in one instance compares less-than the corresponding field in the other instance, regardless of the equality (or lack of) in the other fields. So you are breaking SWO, which causes undefined behavior in std::map's lookups.
Try this instead:
struct chainout {
LONG cl;
std::string cs;
bool operator<(const chainout &o) const {
/*
if (cl < o.cl) return true;
if (cl == o.cl) return (cs < o.cs);
return false;
*/
return (cl < o.cl) || ((cl == o.cl) && (cs < o.cs));
}
};
struct chainin{
std::string tm;
std::string tdi;
short mss;
LONG pinid;
bool operator<(const chainin &o) const {
if (mss < o.mss) return true;
if (mss == o.mss) {
if (pinid < o.pinid) return true;
if (pinid == o.pinid) return (tm < o.tm);
}
return false;
}
};
An easier way to implement this is to use std::tie() instead, which has its own operator< to handle this for you, eg:
struct chainout {
LONG cl;
std::string cs;
bool operator<(const chainout &o) const {
return std::tie(cl, cs) < std::tie(o.cl, o.cs);
}
};
struct chainin{
std::string tm;
std::string tdi;
short mss;
LONG pinid;
bool operator<(const chainin &o) const {
return std::tie(mss, pinid, tm) < std::tie(o.mss, o.pinid, o.tm);
}
};
Either way, then std::map::find() should work as expected, eg:
std::map<chainin, chainout> chainmap;
string FADEDevicePinInfo::getNetAtPinIdTmTidMss (const LONG p, const string tm, const string tid, const LONG mss)
{
chainin ci;
ci.tm = tm;
//ci.tdi = tid;
ci.tdi = "";
ci.mss = (short) mss;
ci.pinid = p;
std::map<chainin, chainout>::iterator it = chainmap.find(ci);
if (it != chainmap.end()) {
cout << "BDEBUG: found"
<< " p[" << it->first.pinid << "]"
<< " tm[" << it->first.tm << "]"
<< " mss[" << it->first.mss << "]"
<< " : " << it->second.cs
<< endl;
}
}

Coordinate iterator of point

How can I get a coordinate iterator of a Point p where Point is fulfilling the Point Concept?
It depends what's the Point type exactly. If you're using bg::model::point<> then this may be problematic since the run-time to compile-time translation of dimension index is needed, so e.g. some number of if conditions in a for-loop or recursive function (as you implemented).
However you could also implement your own Point type and define whatever members you need (e.g. operator[]) or use Point type already implemented in another library (assuming that max dimension is known at compile-time). Then, to let know Boost.Geometry how to handle your Point type you'd be forced to adapt it to Point concept by:
using macros provided by Boost.Geometry for typical 2D and 3D cases
specializing traits the same way how it's done e.g. for model::point_xy<> or model::point<>
I need a coordinate iterator to calculate the smallest enclosing ball (minimum bounding sphere/circle) of points of a (boost geometry) linestring using this library. The following solution contains a modified version of this example at the end:
#include <boost/geometry.hpp>
#include "Miniball.hpp"
namespace bg = boost::geometry;
template<std::size_t>
struct int2type {
};
template<class Point, std::size_t I>
typename bg::coordinate_type<Point>::type
get_imp(std::size_t index, const Point &point, int2type<I>) {
return (I == index)
? bg::get<I>(point)
: get_imp(index, point, int2type<I - 1>());
}
template<class Point>
typename bg::coordinate_type<Point>::type
get_imp(std::size_t index, const Point &point, int2type<0>) {
return bg::get<0>(point);
}
template<class Point>
typename bg::coordinate_type<Point>::type
get(std::size_t index, const Point &point) {
static std::size_t const size = bg::dimension<Point>::value;
return get_imp(index, point, int2type<size - 1>());
}
template<class Point, std::size_t I>
void set_imp(std::size_t index,
Point &point,
typename bg::coordinate_type<Point>::type value,
int2type<I>) {
return (I == index)
? bg::set<I>(point, value)
: set_imp(index, point, value, int2type<I - 1>());
}
template<class Point>
void set_imp(std::size_t index,
Point &point,
typename bg::coordinate_type<Point>::type value,
int2type<0>) {
return bg::set<0>(point, value);
}
template<class Point>
void set(std::size_t index, Point &point, typename bg::coordinate_type<Point>::type value) {
static std::size_t const size = bg::dimension<Point>::value;
return set_imp(index, point, value, int2type<size - 1>());
}
template<class Point>
class CoordinateIterator {
using self_t = CoordinateIterator<Point>;
public:
using iterator_category = std::forward_iterator_tag;
using value_type = typename bg::coordinate_type<Point>::type;
using difference_type = std::size_t;
using pointer = value_type *;
using reference = value_type &;
private:
Point _point;
difference_type _pos;
public:
CoordinateIterator()
: CoordinateIterator(Point()) {}
CoordinateIterator(Point point)
: CoordinateIterator(point, 0) {}
CoordinateIterator(Point point, difference_type pos)
: _point(point), _pos(pos) {}
inline value_type operator*() {
return get(_pos, _point);
}
inline const value_type operator*() const {
return get(_pos, _point);
}
inline self_t &operator++() {
++_pos;
return *this;
}
inline self_t operator++(int) {
self_t copy(*this);
++_pos;
return copy;
}
};
template<typename Linestring>
struct CoordinateAccessor {
using Pit = typename Linestring::const_iterator;
using Cit = CoordinateIterator<typename bg::point_type<Linestring>::type>;
inline Cit operator()(Pit it) const { return Cit(*it); }
};
int main(int argc, char *argv[]) {
using point = bg::model::point<double, 2, bg::cs::cartesian>;
using linestring = bg::model::linestring<point>;
using coordinate_type = bg::coordinate_type<linestring>::type;
using PointIterator = CoordinateAccessor<linestring>::Pit;
const int dimension = bg::dimension<linestring>::value;
const int numberOfPoints = 1000000;
// initialize random number generator
const double seed = (argc != 2) ? 0 : std::atoi(argv[1]);
std::srand(seed);
// generate random points and store them in a linestring
// ----------------------------------------------------------
linestring line;
for (int i = 0; i < numberOfPoints; ++i) {
point p;
for (int j = 0; j < dimension; ++j) {
set(j, p, rand());
}
bg::append(line, p);
}
// create an instance of Miniball
// ------------------------------
using MB = Miniball::Miniball<CoordinateAccessor<linestring>>;
MB mb(dimension, line.begin(), line.end());
// output results
// --------------
// center
std::cout << "Center:\n ";
const coordinate_type *center = mb.center();
for (int i = 0; i < dimension; ++i, ++center)
std::cout << *center << " ";
std::cout << std::endl;
// squared radius
std::cout << "Squared radius:\n ";
std::cout << mb.squared_radius() << std::endl;
// number of support points
std::cout << "Number of support points:\n ";
std::cout << mb.nr_support_points() << std::endl;
// support points on the boundary determine the smallest enclosing ball
std::cout << "Support point indices (numbers refer to the input order):\n ";
MB::SupportPointIterator it = mb.support_points_begin();
PointIterator first = line.begin();
for (; it != mb.support_points_end(); ++it) {
std::cout << std::distance(first, *it) << " "; // 0 = first point
}
std::cout << std::endl;
// relative error: by how much does the ball fail to contain all points?
// tiny positive numbers come from roundoff and are ok
std::cout << "Relative error:\n ";
coordinate_type suboptimality;
std::cout << mb.relative_error(suboptimality) << std::endl;
// suboptimality: by how much does the ball fail to be the smallest
// enclosing ball of its support points? should be 0
// in most cases, but tiny positive numbers are again ok
std::cout << "Suboptimality:\n ";
std::cout << suboptimality << std::endl;
// validity: the ball is considered valid if the relative error is tiny
// (<= 10 times the machine epsilon) and the suboptimality is zero
std::cout << "Validity:\n ";
std::cout << (mb.is_valid() ? "ok" : "possibly invalid") << std::endl;
// computation time
std::cout << "Computation time was " << mb.get_time() << " seconds\n";
return 0;
}

Different return and coordinate types in nanoflann radius search

I'm trying to use nanoflann in a project and am looking at the vector-of-vector and radius search examples.
I can't find a way to perform a radius search with a different data type than the coordinate type. For example, my coordinates are vectors of uint8_t; I am trying to input a radius of type uint32_t with little success.
I see in the source that the metric_L2 struct (which I am using for distance) uses the L2_Adaptor with two template parameters. L2_Adaptor itself takes three parameters, with the third defaulted to the first, which seems to be the problem if I am understanding the code correctly. However, trying to force use of the third always results in 0 matches in the radius search.
Is there a way to do this?
Edit: In the same code below, everything works. However, if I change the search_radius (and ret_matches) to uint32_t, the radiusSearch method doesn't work.
#include <iostream>
#include <Eigen/Dense>
#include <nanoflann.hpp>
typedef Eigen::Matrix<uint8_t, Eigen::Dynamic, 1> coord_t;
using namespace nanoflann;
struct Point
{
coord_t address;
Point() {}
Point(uint8_t coordinates) : address(coord_t::Random(coordinates)) {}
};
struct Container
{
std::vector<Point> points;
Container(uint8_t coordinates, uint32_t l)
: points(l)
{
for(auto& each_location: points)
{
each_location = Point(coordinates);
}
}
};
struct ContainerAdaptor
{
typedef ContainerAdaptor self_t;
typedef nanoflann::metric_L2::traits<uint8_t, self_t>::distance_t metric_t;
typedef KDTreeSingleIndexAdaptor<metric_t, self_t, -1, size_t> index_t;
index_t *index;
const Container &container;
ContainerAdaptor(const int dimensions, const Container &container, const int leaf_max_size = 10)
: container(container)
{
assert(container.points.size() != 0 && container.points[0].address.rows() != 0);
const size_t dims = container.points[0].address.rows();
index = new index_t(dims, *this, nanoflann::KDTreeSingleIndexAdaptorParams(leaf_max_size));
index->buildIndex();
}
~ContainerAdaptor()
{
delete index;
}
inline void query(const uint8_t *query_point, const size_t num_closest, size_t *out_indices, uint32_t *out_distances_sq, const int ignoreThis = 10) const
{
nanoflann::KNNResultSet<uint32_t, size_t, size_t> resultSet(num_closest);
resultSet.init(out_indices, out_distances_sq);
index->findNeighbors(resultSet, query_point, nanoflann::SearchParams());
}
const self_t& derived() const
{
return *this;
}
self_t& derived()
{
return *this;
}
inline size_t kdtree_get_point_count() const
{
return container.points.size();
}
inline size_t kdtree_distance(const uint8_t *p1, const size_t idx_p2, size_t size) const
{
size_t s = 0;
for (size_t i = 0; i < size; i++)
{
const uint8_t d = p1[i] - container.points[idx_p2].address[i];
s += d * d;
}
return s;
}
inline coord_t::Scalar kdtree_get_pt(const size_t idx, int dim) const
{
return container.points[idx].address[dim];
}
template <class BBOX>
bool kdtree_get_bbox(BBOX & bb) const
{
for(size_t i = 0; i < bb.size(); i++)
{
bb[i].low = 0;
bb[i].high = UINT8_MAX;
}
return true;
}
};
void container_demo(const size_t points, const size_t coordinates)
{
Container s(coordinates, points);
coord_t query_pt(coord_t::Random(coordinates));
typedef ContainerAdaptor my_kd_tree_t;
my_kd_tree_t mat_index(coordinates, s, 25);
mat_index.index->buildIndex();
const uint8_t search_radius = static_cast<uint8_t>(100);
std::vector<std::pair<size_t, uint8_t>> ret_matches;
nanoflann::SearchParams params;
const size_t nMatches = mat_index.index->radiusSearch(query_pt.data(), search_radius, ret_matches, params);
for (size_t i = 0; i < nMatches; i++)
{
std::cout << "idx[" << i << "]=" << +ret_matches[i].first << " dist[" << i << "]=" << +ret_matches[i].second << std::endl;
}
std::cout << std::endl;
std::cout << "radiusSearch(): radius=" << +search_radius << " -> " << +nMatches << " matches" << std::endl;
}
int main()
{
container_demo(1e6, 32);
return 0;
}
More info: so it seems that the distance type, which the third parameter of the L2_Adaptor, must be a signed type. Changing the metric_t typedef to the following solves the problem if search_radius and ret_matches are also changed to int64_t.
typedef L2_Adaptor<uint8_t, self_t, int64_t> metric_t;

How to make this matching algorithm run faster?

I have two lists of pointers to a data structure X, the algorithm is very simple:
It loops over the first list A and try to find the the first matching element in list B. The requirement is to have at least 50k elements in each list:
#include <iostream>
#include <memory>
#include <chrono>
#include <vector>
#include <algorithm>
#include <string>
struct X {
std::string field_1;
std::string field_2;
std::string field_3;
std::string field_4;
X(std::string f1, std::string f2, std::string f3, std::string f4)
: field_1(f1)
, field_2(f2)
, field_3(f3)
, field_4(f4)
{};
bool equal(const std::shared_ptr<X>& x) {
return (x->field_1 == field_1) &&
(x->field_2 == field_2) &&
(x->field_3 == field_3) &&
(x->field_4 == field_4);
};
X *match = nullptr;
};
typedef std::shared_ptr<X> X_ptr;
class Timer
{
public:
Timer(std::string name) : beg_(clock_::now()), name_(name) {}
~Timer() {
std::cout << "Elapsed(" << name_ << "): " << elapsed() << std::endl;
}
void reset() { beg_ = clock_::now(); }
double elapsed() const {
return std::chrono::duration_cast<second_>
(clock_::now() - beg_).count();
}
private:
typedef std::chrono::high_resolution_clock clock_;
typedef std::chrono::duration<double, std::ratio<1> > second_;
std::chrono::time_point<clock_> beg_;
std::string name_;
};
std::string random_string(size_t length)
{
auto randchar = []() -> char
{
const char charset[] =
"0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const size_t max_index = (sizeof(charset) - 1);
return charset[rand() % max_index];
};
std::string str(length, 0);
std::generate_n(str.begin(), length, randchar);
return str;
}
int main()
{
Timer t("main");
std::vector <X_ptr> list_A;
std::vector <X_ptr> list_B;
const int MAX_ELEM = 50000;
list_A.reserve(MAX_ELEM);
list_B.reserve(MAX_ELEM);
{
Timer t("insert");
for (int i = 0; i < MAX_ELEM; i++) {
list_A.push_back(X_ptr(new X{ random_string(2), random_string(2), random_string(2), random_string(2) }));
list_B.push_back(X_ptr(new X{ random_string(2), random_string(2), random_string(2), random_string(2) }));
}
}
{
Timer t("match");
std::for_each(list_A.begin(), list_A.end(), [list_B](X_ptr& a) {
auto found_b = std::find_if(list_B.begin(), list_B.end(), [a](const X_ptr& b) {
return a->equal(b);
});
if (found_b != list_B.end()) {
a->match = found_b->get();
std::cout << "match OK \n";
}
});
}
}
on my machine the program is running extremly slow:
Elapsed(insert): 0.05566
Elapsed(match): 98.3739
Elapsed(main): 98.452
Would appreciate it if you can think of any other way to optimize it to run faster.
You are using vectors so each lookup into list_B takes O(n), where n is the number of elements in B. This means the total algorithm is O(m*n), if m is the number of elements in list_A. Thus if m and n a similar in size, you have a O(n^2) algorithm. That is too slow for any large n. To fix this, convert list_B into a unordered_map, (you can do this as part of this algorithm as the conversion is O(n)) where an element in the map's key is an element from list B and the value anything, say 0. You can then perform lookups into the map in O(1) time using find() on the map. Thus your algorithm becomes O(n), way better that O(n^2).
For example
std::unordered_map< X_ptr, int > value_map;
Time r t("match");
std::for_each(list_B.begin(), list_B.end(), [&](X_ptr& b) {
value_map[b] = 0;
});
std::for_each(list_A.begin(), list_A.end(), [value_map](X_ptr& a) {
auto found_b = value_map.find( a );
if ( found_b != value_map.end() )
{
a->match = found_b->first.get();
std::cout << "match OK \n";
}
});
}
Your Version:
Elapsed(insert): 0.0758608
Elapsed(match): 182.899
Elapsed(main): 182.991
New Version:
Elapsed(insert): 0.0719907
Elapsed(match): 0.0388562
Elapsed(main): 0.130884
You may use something like the following:
std::sort(list_B.begin(), list_B.end(), deref_less<X>);
{
Timer t("match");
for (const auto& a : list_A) {
auto it = std::lower_bound(list_B.begin(), list_B.end(), a, deref_less<X>);
if (it != list_B.end() && **it == *a) {
a->match = it->get();
std::cout << "match OK \n";
}
}
}
Live example.

How do I find an element position in std::vector?

I need to find an element position in an std::vector to use it for referencing an element in another vector:
int find( const vector<type>& where, int searchParameter )
{
for( int i = 0; i < where.size(); i++ ) {
if( conditionMet( where[i], searchParameter ) ) {
return i;
}
}
return -1;
}
// caller:
const int position = find( firstVector, parameter );
if( position != -1 ) {
doAction( secondVector[position] );
}
however vector::size() returns size_t which corresponds to an unsigned integral type that can't directly store -1. How do I signal that the element is not found in a vector when using size_t instead of int as an index?
Take a look at the answers provided for this question: Invalid value for size_t?. Also you can use std::find_if with std::distance to get the index.
std::vector<type>::iterator iter = std::find_if(vec.begin(), vec.end(), comparisonFunc);
size_t index = std::distance(vec.begin(), iter);
if(index == vec.size())
{
//invalid
}
First of all, do you really need to store indices like this? Have you looked into std::map, enabling you to store key => value pairs?
Secondly, if you used iterators instead, you would be able to return std::vector.end() to indicate an invalid result. To convert an iterator to an index you simply use
size_t i = it - myvector.begin();
You could use std::numeric_limits<size_t>::max() for elements that was not found. It is a valid value, but it is impossible to create container with such max index. If std::vector has size equal to std::numeric_limits<size_t>::max(), then maximum allowed index will be (std::numeric_limits<size_t>::max()-1), since elements counted from 0.
std::vector has random-access iterators. You can do pointer arithmetic with them. In particular, this my_vec.begin() + my_vec.size() == my_vec.end() always holds. So you could do
const vector<type>::const_iterator pos = std::find_if( firstVector.begin()
, firstVector.end()
, some_predicate(parameter) );
if( position != firstVector.end() ) {
const vector<type>::size_type idx = pos-firstVector.begin();
doAction( secondVector[idx] );
}
As an alternative, there's always std::numeric_limits<vector<type>::size_type>::max() to be used as an invalid value.
In this case, it is safe to cast away the unsigned portion unless your vector can get REALLY big.
I would pull out the where.size() to a local variable since it won't change during the call. Something like this:
int find( const vector<type>& where, int searchParameter ){
int size = static_cast<int>(where.size());
for( int i = 0; i < size; i++ ) {
if( conditionMet( where[i], searchParameter ) ) {
return i;
}
}
return -1;
}
If a vector has N elements, there are N+1 possible answers for find. std::find and std::find_if return an iterator to the found element OR end() if no element is found. To change the code as little as possible, your find function should return the equivalent position:
size_t find( const vector<type>& where, int searchParameter )
{
for( size_t i = 0; i < where.size(); i++ ) {
if( conditionMet( where[i], searchParameter ) ) {
return i;
}
}
return where.size();
}
// caller:
const int position = find( firstVector, parameter );
if( position != secondVector.size() ) {
doAction( secondVector[position] );
}
I would still use std::find_if, though.
Something like this, I think. find_if_counted.hpp:
#ifndef FIND_IF_COUNTED_HPP
#define FIND_IF_COUNTED_HPP
#include <algorithm>
namespace find_if_counted_impl
{
template <typename Func>
struct func_counter
{
explicit func_counter(Func& func, unsigned &count) :
_func(func),
_count(count)
{
}
template <typename T>
bool operator()(const T& t)
{
++_count;
return _func(t);
}
private:
Func& _func;
unsigned& _count;
};
}
// generic find_if_counted,
// returns the index of the found element, otherwise returns find_if_not_found
const size_t find_if_not_found = static_cast<size_t>(-1);
template <typename InputIterator, typename Func>
size_t find_if_counted(InputIterator start, InputIterator finish, Func func)
{
unsigned count = 0;
find_if_counted_impl::func_counter<Func> f(func, count);
InputIterator result = find_if(start, finish, f);
if (result == finish)
{
return find_if_not_found;
}
else
{
return count - 1;
}
}
#endif
Example:
#include "find_if_counted.hpp"
#include <cstdlib>
#include <iostream>
#include <vector>
typedef std::vector<int> container;
int rand_number(void)
{
return rand() % 20;
}
bool is_even(int i)
{
return i % 2 == 0;
}
int main(void)
{
container vec1(10);
container vec2(10);
std::generate(vec1.begin(), vec1.end(), rand_number);
std::generate(vec2.begin(), vec2.end(), rand_number);
unsigned index = find_if_counted(vec1.begin(), vec1.end(), is_even);
if (index == find_if_not_found)
{
std::cout << "vec1 has no even numbers." << std::endl;
}
else
{
std::cout << "vec1 had an even number at index: " << index <<
" vec2's corresponding number is: " << vec2[index] << std::endl;
}
}
Though I feel like I'm doing something silly... :X Any corrections are welcome, of course.
You probably should not use your own function here.
Use find() from STL.
Example:
list L;
L.push_back(3);
L.push_back(1);
L.push_back(7);
list::iterator result = find(L.begin(), L.end(), 7);
assert(result == L.end() || *result == 7);
Take a vector of integer and a key (that we find in vector )....Now we are traversing the vector until found the key value or last index(otherwise).....If we found key then print the position , otherwise print "-1".
#include <bits/stdc++.h>
using namespace std;
int main()
{
vector<int>str;
int flag,temp key, ,len,num;
flag=0;
cin>>len;
for(int i=1; i<=len; i++)
{
cin>>key;
v.push_back(key);
}
cin>>num;
for(int i=1; i<=len; i++)
{
if(str[i]==num)
{
flag++;
temp=i-1;
break;
}
}
if(flag!=0) cout<<temp<<endl;
else cout<<"-1"<<endl;
str.clear();
return 0;
}
Get rid of the notion of vector entirely
template< typename IT, typename VT>
int index_of(IT begin, IT end, const VT& val)
{
int index = 0;
for (; begin != end; ++begin)
{
if (*begin == val) return index;
}
return -1;
}
This will allow you more flexibility and let you use constructs like
int squid[] = {5,2,7,4,1,6,3,0};
int sponge[] = {4,2,4,2,4,6,2,6};
int squidlen = sizeof(squid)/sizeof(squid[0]);
int position = index_of(&squid[0], &squid[squidlen], 3);
if (position >= 0) { std::cout << sponge[position] << std::endl; }
You could also search any other container sequentially as well.