Reputation: 66244
I have a std::vector
with n
elements. Now I need to pass a pointer to a vector that has the last n-1
elements to a function.
For example, my vector<int> foo
contains (5,2,6,87,251)
. A function takes vector<int>*
and I want to pass it a pointer to (2,6,87,251)
.
Can I just (safely) take the iterator ++foo.begin()
, convert it to a pointer and pass that to the function? Or use &foo[1]
?
UPDATE: People suggest that I change my function to take an iterator rather than a pointer. That seems not possible in my situation, since the function I mentioned is the find
function of unordered_set<std::vector*>
. So in that case, is copying the n-1
elements from foo
into a new vector and calling find
with a pointer to that the only option? Very inefficient! It's like Shlemiel the painter, especially since i have to query many subsets: the last n-1
, then n-2
, etc. elements and see if they are in the unordered_set
.
Upvotes: 75
Views: 148818
Reputation: 1
std::vector<int> v;
:
auto it=v.end();
auto ptr=v.data()+std::distance(v.begin(),it);
Upvotes: -1
Reputation: 1546
A safe version to convert an iterator to a pointer (exactly what that means regardless of the implications) and by safe I mean no worries about having to dereference the iterator and cause possible exceptions / errors due to end()
/ other situations
#include <iostream>
#include <vector>
#include <string.h>
int main()
{
std::vector<int> vec;
char itPtr[25];
long long itPtrDec;
std::vector<int>::iterator it = vec.begin();
memset(&itPtr, 0, 25);
sprintf(itPtr, "%llu", it);
itPtrDec = atoll(itPtr);
printf("it = 0x%X\n", itPtrDec);
vec.push_back(123);
it = vec.begin();
memset(&itPtr, 0, 25);
sprintf(itPtr, "%llu", it);
itPtrDec = atoll(itPtr);
printf("it = 0x%X\n", itPtrDec);
}
will print something like
it = 0x0
it = 0x2202E10
It's an incredibly hacky way to do it, but if you need it, it does the job. You will receive some compiler warnings which, if really bothering you, can be removed with #pragma
Upvotes: 0
Reputation: 11
Vector is a template class and it is not safe to convert the contents of a class to a pointer : You cannot inherit the vector class to add this new functionality. and changing the function parameter is actually a better idea. Jst create another vector of int vector temp_foo (foo.begin[X],foo.end()); and pass this vector to you functions
Upvotes: 0
Reputation: 6751
here it is, obtaining a reference to the coresponding pointer of an iterator use :
example:
string my_str= "hello world";
string::iterator it(my_str.begin());
char* pointer_inside_buffer=&(*it); //<--
[notice operator * returns a reference so doing & on a reference will give you the address].
Upvotes: 136
Reputation: 21956
Use vector::front
, it should be the most portable solution. I've used this when I'm interfacing with a fixed API that wants a char ptr. Example:
void funcThatTakesCharPtr(char* start, size_t size);
...
void myFunc(vector<char>& myVec)
{
// Get a pointer to the front element of my vector:
char* myDataPtr = &(myVec.front());
// Pass that pointer to my external API:
funcThatTakesCharPtr(myDataPtr, myVec.size());
}
Upvotes: 2
Reputation: 25710
A vector is a container with full ownership of it's elements. One vector cannot hold a partial view of another, even a const-view. That's the root cause here.
If you need that, make your own container that has views with weak_ptr's to the data, or look at ranges. Pair of iterators (even pointers work well as iterators into a vector) or, even better, boost::iterator_range that work pretty seamlessly.
It depends on the templatability of your code. Use std::pair if you need to hide the code in a cpp.
Upvotes: 3
Reputation: 9408
I haven't tested this but could you use a set of pairs of iterators instead? Each iterator pair would represent the begin and end iterator of the sequence vector. E.g.:
typedef std::vector<int> Seq;
typedef std::pair<Seq::const_iterator, Seq::const_iterator> SeqRange;
bool operator< (const SeqRange& lhs, const SeqRange& rhs)
{
Seq::const_iterator lhsNext = lhs.first;
Seq::const_iterator rhsNext = rhs.first;
while (lhsNext != lhs.second && rhsNext != rhs.second)
if (*lhsNext < *rhsNext)
return true;
else if (*lhsNext > *rhsNext)
return false;
return false;
}
typedef std::set<SeqRange, std::less<SeqRange> > SeqSet;
Seq sequences;
void test (const SeqSet& seqSet, const SeqRange& seq)
{
bool find = seqSet.find (seq) != seqSet.end ();
bool find2 = seqSet.find (SeqRange (seq.first + 1, seq.second)) != seqSet.end ();
}
Obviously the vectors have to be held elsewhere as before. Also if a sequence vector is modified then its entry in the set would have to be removed and re-added as the iterators may have changed.
Jon
Upvotes: 0
Reputation: 101506
The direct answer to your question is yes. If foo is a vector, you can do this: &foo[1].
This only works for vectors however, because the standard says that vectors implement storage by using contigious memory.
But you still can (and probably should) pass iterators instead of raw pointers because it is more expressive. Passing iterators does not make a copy of the vector.
Upvotes: 2
Reputation: 340476
For example, my
vector<int> foo
contains (5,2,6,87,251). A function takesvector<int>*
and I want to pass it a pointer to (2,6,87,251).
A pointer to a vector<int>
is not at all the same thing as a pointer to the elements of the vector.
In order to do this you will need to create a new vector<int>
with just the elements you want in it to pass a pointer to. Something like:
vector<int> tempVector( foo.begin()+1, foo.end());
// now you can pass &tempVector to your function
However, if your function takes a pointer to an array of int, then you can pass &foo[1]
.
Upvotes: 2
Reputation: 24338
That seems not possible in my situation, since the function I mentioned is the find function of
unordered_set<std::vector*>
.
Are you using custom hash/predicate function objects? If not, then you must pass unordered_set<std::vector<int>*>::find()
the pointer to the exact vector that you want to find. A pointer to another vector with the same contents will not work. This is not very useful for lookups, to say the least.
Using unordered_set<std::vector<int> >
would be better, because then you could perform lookups by value. I think that would also require a custom hash function object because hash
does not to my knowledge have a specialization for vector<int>
.
Either way, a pointer into the middle of a vector is not itself a vector, as others have explained. You cannot convert an iterator into a pointer to vector without copying its contents.
Upvotes: 7
Reputation: 89849
If you can, a better choice may be to change the function to take either an iterator to an element or a brand new vector (if it does not modify).
While you can do this sort of things with arrays since you know how they are stored, it's probably a bad idea to do the same with vectors. &foo[1]
does not have the type vector<int>*
.
Also, while the STL implementation is available online, it's usually risky to try and rely on the internal structure of an abstraction.
Upvotes: 6
Reputation: 135443
If your function really takes vector<int> *
(a pointer to vector), then you should pass &foo
since that will be a pointer to the vector. Obviously that will not simply solve your problem, but you cannot directly convert an iterator to a vector, since the memory at the address of the iterator will not directly address a valid vector.
You can construct a new vector by calling the vector constructor:
template <class InputIterator> vector(InputIterator, InputIterator)
This constructs a new vector by copying the elements between the two iterators. You would use it roughly like this:
bar(std::vector<int>(foo.begin()+1, foo.end());
Upvotes: 0
Reputation: 223183
Your function shouldn't take vector<int>*
; it should take vector<int>::iterator
or vector<int>::const_iterator
as appropriate. Then, just pass in foo.begin() + 1
.
Upvotes: 4