I have a large size of vector and I want extract its subvector based on index. But I do not want to make a new copy of a subvector.
Can I use pointer a iterator to return the pointer of the original vector?
something like:
vector<int> orig = { 0,1,2,3,4,5,6,7,8,9 };
vector<int> index = { 3,5,6,8 };
vector<int> dest (vector<int> orig, vector<int> index)
{
....
}
What I want get is get dest as { 3,5,6,8 } and it is point to orig but not the new copy.
(index is the index vector of what I want to extract from the original vector)
Or, can I use smart pointer to do this?
You won't be able to create a std::vector<T> from a subrange of another std::vector<T>. However, you could travel in terms of a view which stores iterators into a std::vector<T> which is owning the actual values:
template <typename Iterator>
class array_view {
Iterator begin_;
Iterator end_;
public:
// ...
array_view(Iterator begin, Iterator end): begin_(begin), end_(end) {}
Iterator begin() const { return this->begin_; }
Iterator end() const { return this->end_; }
typename std::iterator_traits<Iterator>::reference
operator[](std::size_t index) { return this->begin_[index]; }
};
Things get a bit interesting if you want to deal with the same type independently of who owns the actual array. In that case you might want to create something like the array_view<T> above but also storing a std::shared_ptr<std::vector<T>> for the underlying representation (and if you need to modify the original representation, you'd store offsets instead of iterators).
Every time I say I've sworn off std::valarray, somebody brings up a problem like this that valarray supports quite directly. For example:
std::valarray<int> orig = { 0,1,2,3,4,5,6,7,8,9 };
std::valarray<size_t> index = { 3,5,6,8 };
orig[index] = -1;
Then if (for example) we print out the elements of orig with code like this:
for (int i=0; i<orig.size(); i++)
std::cout << orig[i] << "\t";
... we get the following results:
0 1 2 -1 4 -1 -1 7 -1 9
If you want the vector to be mutable, no. If you just want to pass a subvector around but not change the contents, why not change your various functions to take a start and end iterator rather than be passed a vector?
Related
I am finding trouble inserting an object into a std::vector, following the example of what I'm trying to do:
//in SomeClass.cpp
void SomeClass::addItem(int32_t &position, OtherClass &value)
{
vectorOtherClass.insert(position,valvalue);
}
however I get the following error when trying to compile the program:
error: no matching function for call to ‘std::vector::insert(int32_t&, OtherClass&)’
vectorOtherClass.insert(position,value);
______________________^
the vector definition in SomeClass.h is:
private:
std::vector<OtherClass> vectorOtherClass;
How can I properly insert an object into a vector in C ++?
And one last question, are the objects stored by reference or by copy within the vector?
Like the error says, there is no insert function with int parameter. See:
single element (1)
iterator insert (iterator position, const value_type& val);
fill (2)
void insert (iterator position, size_type n, const value_type& val);
range (3)
template <class InputIterator>
void insert (iterator position, InputIterator first, InputIterator last);
You can find an example here http://www.cplusplus.com/reference/vector/vector/insert/
int main ()
{
std::vector<int> myvector (3,100);
std::vector<int>::iterator it;
it = myvector.begin();
it = myvector.insert ( it , 200 );
myvector.insert (it,2,300);
// "it" no longer valid, get a new one:
it = myvector.begin();
std::vector<int> anothervector (2,400);
myvector.insert (it+2,anothervector.begin(),anothervector.end());
int myarray [] = { 501,502,503 };
myvector.insert (myvector.begin(), myarray, myarray+3);
std::cout << "myvector contains:";
for (it=myvector.begin(); it<myvector.end(); it++)
std::cout << ' ' << *it;
std::cout << '\n';
return 0;
}
According to the method's reference, the insert method takes the following parameters:
position
Position in the vector where the new elements are inserted.
iterator is a member type, defined as a random access iterator type that points to elements.
val
Value to be copied (or moved) to the inserted elements.
Member type value_type is the type of the elements in the container, defined in deque as an alias of its first template parameter (T).
Note that position is not an integral value, but rather an iterator. C++ use iterators a lot, since many operations are fairly efficient when you have one.
In particular, you can add vector iterators and numbers to get the iterator to the correct position, so you can do something like:
vectorOtherClass.insert(vectorOtherClass.begin() + position, value);
This does not apply to other containers such as std::list. Also, you should make sure to check position is within the bounds of the vector (0 <= position < vectorOtherClass.size()). Ideally, position should be unsigned to ensure the lower bound.
Lastly, elements are added to std::vectors as copies. Vectors use an array internally, so values are copied into it. The array is resized (copied and replaced) as needed.
Refer to: http://en.cppreference.com/w/cpp/container/vector/insert
You need to pass in an interator, so use begin and offset the position from there. No need to pass in ints by ref unless your function is going to change them. Consider checking for buffer overflow.
void SomeClass::addItem(int32_t position, const OtherClass &value)
{
assert(position < vectorOtherClass.size());
assert(position >= 0);
vectorOtherClass.insert(vectorOtherClass.begin()+position, value);
}
I have a std::vector<int> and I want to throw away the x first and y last elements. Just copying the elements is not an option, since this is O(n).
Is there something like vector.begin()+=x to let the vector just start later and end earlier?
I also tried
items = std::vector<int> (&items[x+1],&items[0]+items.size()-y);
where items is my vector, but this gave me bad_alloc
C++ standard algorithms work on ranges, not on actual containers, so you don't need to extract anything: you just need to adjust the iterator range you're working with.
void foo(const std::vector<T>& vec, const size_t start, const size_t end)
{
assert(vec.size() >= end-start);
auto it1 = vec.begin() + start;
auto it2 = vec.begin() + end;
std::whatever(it1, it2);
}
I don't see why it needs to be any more complicated than that.
(trivial live demo)
If you only need a range of values, you can represent that as a pair of iterators from first to last element of the range. These can be acquired in constant time.
Edit: According to the description in the comments, this seems like the most sensible solution. If your functions expect a vector reference, then you'll need to refactor a bit.
Other solutions:
If you don't need the original vector, and therefore can modify it, and the order of elements is not relevant, you can swap the first x elements with the n-x-y...n-y elements and then remove the last x+y elements. This can be done in O(x+y) time.
If appropriate, you could choose to use std::list for which what you're asking can be done in constant time if you have iterators to the first and last node of the sublist. This also requires that you can modify the original list but the order of elements won't change.
If those are not options, then you need to copy and are stuck with O(n).
The other answers are correct: usually iterators will do.
Nevertheless, you can also write a vector view. Here is a sketch:
template<typename T>
struct vector_view
{
vector_view(std::vector<T> const& v, size_t ind_begin, size_t ind_end)
: _v(v)
, _size(/* size of range */)
, _ind_begin(ind_begin) {}
auto size() const { return _size; }
auto const& operator[](size_t i) const
{
//possibly check for input outside range
return _v[ i + _ind_begin ];
}
//conversion of view to std::vector
operator std::vector<T>() const
{
std::vector<T> ret(_size);
//fill it
return ret;
}
private:
std::vector<T> const& _v;
size_t _size;
size_t _ind_begin;
}
Expose further methods as required (some iterator stuff might be appropriate when you want to use that with the standard library algorithms).
Further, take care on the validity of the const reference std::vector<T> const& v; -- if that could be an issue, one should better work with shared-pointers.
One can also think of more general approaches here, for example, use strides or similar things.
I have a class containing a dynamic array and I want to iterate through it using begin() and end(). The problem is that I can't seem to get the iteration part to work correctly. So far it looks something like this:
template<typename T>
class Deque {
T** _deque;
int _front;
int _back;
public:
Deque() {
_deque = new T*[10];
_front = 5;
_back = 5;
}
// push_back and push_front add elements to the list and move _front/_back
// ...
T* begin() {
return _deque[_front];
}
T* end() {
return _deque[_back];
}
};
But if I add a few items to the list with push_back and push_front (which work perfectly) then try this
for (auto i : deque) {
cout << i << endl;
}
The first item will always be correct but all following objects will be garbage and will often exceed the size of the array.
How can I automatically iterate over this structure given it's constrained between _front and _back?
You haven't shown where _deque gets filled in, but it is probably from a whole bunch of separate allocations?
The issue is that to iterate through an array, you need to point into it. But you are reading from the array.
A pointer into _deque would be begin() { return _deque + _front; } end() { return _deque + _back; } and would have type T**.
What you have now is morally equivalent to:
std::vector<T*> v;
...
auto it = *(v.begin()); // this is the first pointer stored *in* the container,
// not a pointer to the beginning of the container
auto end = *(v.end()); // this is not even the last pointer stored in the container,
// it is reading the element past the end!
for( ; it != end; ++it )
which is quite different from the correct iteration:
auto it = v.begin();
auto end = v.end();
for( ; it != end; ++it )
Most likely your _deque variable should have type T*, not T**, and if you want to store pointers, let T be a pointer type.
I have an assignment that's been driving me insane. I've been researching basic concepts to increase my knowledge and try to apply it to this problem but I'm a bit stuck.
We have a main.cpp file that tests a VectorOfVectors class that has this syntax:
for( int num : intVov )
{
printf( "%d ", num );
}
We're creating our own VectorOfVectors class with templated vectors as items.
We have to make the main function properly work by creating our own custom iterator that iterates through all the values, as shown by the main function. I've been researching range-based iterators but I'm a little confused as to how to construct my own, and because it is a vector of vectors the syntax does not match well with some online examples.
I would like guidance as to how I can go about creating this iterator. I know I need a begin() and end() function, as well as override the operator++ function to get it to work. Would my iterator use int values as the pointer(s) that I increment in operator++? Would I need two pointers? What would begin() and end() return, iterators, or integers, or T values, or vectors? How should I construct the iterator and what data do I need for it? Would the iterator constructor take two pointers as values, or one, or how would that work? Would the iterator need its own copy of a VectorOfVectors to iterate (and be set in a constructor)?
How would I go about increasing the pointers? Any help, general knowledge or even tips would be greatly appreciated!
Here's what I've been fiddling around, just as a reference.
#include <vector>
using std::vector;
template< typename T > class VectorOfVectors
{
public:
class iterator
{
public:
//Constructor
iterator(const VectorOfVectors<T> * vov, int pos_vov, int pos_v)
{
_pos_vov = pos_vov;
_pos_v = pos_v;
_vov = vov;
}
bool operator!= (const iterator & other) const
{
return pos != other._pos;
}
int operator* () const;
const iterator operator++ ()
{
_pos_v++;
if (_pos_v == _pos_vov->end())
{
_pos_vov++;
if (_pos_vov == _vov.end())
{
--_pos_vov;
_pos_v = _pos_vov->end();
--_pos_v;
return (*this);
}
else
{
_pos_v = _pos_vov->begin();
return (*this);
}
}
else
{
return (*this);
}
}
private:
int _pos_v;
int _pos_vov;
const VectorOfVectors<T> * _vov;
};
void AddEmptyVector()
{
vectorOfVectors.push_back(new vector<T>());
}
int GetVectorCount() const
{
return vectorOfVectors.size();
}
vector<T> GetVectorAtIndex(int index)
{
return vectorOfVectors.at(index);
}
void AddCopyOfVector(vector<T> & toBeAdded)
{
vectorOfVectors.push_back(toBeAdded);
}
iterator begin() const
{
return iter(this, 0, 0);
}
iterator end() const
{
return iterator(this, 4, 3);
}
private:
vector< vector<T> > vectorOfVectors = new vector< vector<T> >();
};
From the for loop that you posted, it seems that the instructor wants the iterator to iterate over individual elements of the vector-of-vectors (rather than, for instance, over the sub-vectors).
begin() and end() must always return iterators, not the elements pointed to by iterators (so e.g. not raw ints in this case). In certain special cases it might be possible to make these raw pointers (for example I think certain STL implementations of std::vector::iterator do this), but generally they will need to be small structs containing enough information to navigate the parent data structure.
See this page for a good description of what the for (var : collection) syntax actually translates to. This tells you that you need to design an iterator type Iter that has the following properties:
*Iter returns a T, or something convertible to T (like T&). You currently have this wrong -- your int operator* () const; (which doesn't appear to be defined?) is returning an int, for some reason.
++Iter moves the iterator to the next element.
Iter1 != Iter2 returns false when the two iterators are pointing at the same element.
How you actually create the Iter type is completely up to you. Using 2 integer indices and checking for "wraparound" on ++ as you're currently doing seems sound to me.
Other notes:
Your begin() currently calls return iter(this, 0, 0);, which won't even compile.
Please don't dynamically allocate pointers to std::vector, as you do in the declaration of vectorOfVectors and in AddEmptyVector(). For a start, neither will compile, because for them to compile you would need to declare vectorOfVectors as a pointer to a vector of pointers to vectors, and you don't want to do that, because std::vector manages its own dynamic memory allocation internally -- avoid having to ever call new and delete is the main reason you use a std::vector in the first place.
My question is twofold:
I have a vector of objects and a vector of integers, I want to iterate on my object vector in the order of the integer vector:
meaning if {water,juice,milk,vodka} is my object vector and {1,0,3,2} is my integer vector I wish to have a const iterator for my object vector that will have juice for the first object, water for the second, vodka and last milk.
is there a simple way of doing this?
suppose I have a function returning const iterator (itr) to a unknown (but accessible) vector
meaning, I can use (itr.getvalue()) but i don't have the size of the vector I'm iterating on, is there a way to make a while loop and know the end or the vector by iterator means?
Question 1:
Omitting most of the boilerplate needed for a proper iterator, the following is how it would work:
template<typename Container, typename Iterator>
class index_iterator
{
public:
typedef typename Container::value_type value_type;
index_iterator(Container& c, Iterator iter):
container(c),
iterator(iter)
{
}
value_type& operator*() { return container[*iterator]; }
index_iterator& operator++() { ++iterator; return *this; }
bool operator==(index_iterator const& other)
{
return &container == &other.container && iterator == other.iterator;
}
// ...
private:
Container& container;
Iterator iterator;
};
template<typename C, typename I>
index_iterator<C, I> indexer(C& container, I iter)
{
return index_iterator<C, I>(container, iter);
}
Then you could write e.g.
std::vector<std::string> vs;
std::vector<int> vi
// fill vs and vi
std::copy(indexer(vs, vi.begin()),
indexer(vs, vi.end()),
std::ostream_iterator<std::string>(std::cout, " "));
Question 2:
No, it isn't possible.
1
#include <iostream>
#include <vector>
std::vector<std::string> foods{"water", "juice", "milk", "vodka"};
std::vector<unsigned int> indexes{1,0,3,2};
for (int i : indexes) { // ranged-for; use normal iteration if you must
std::cout << foods[i] << " ";
}
// Output: juice water vodka milk
Live demo
If you really want to wrap this behaviour into a single iterator for foods, this can be done but it gets a bit more complicated.
2
suppose I have a function returning const iterator (itr) to a unknown (but accessible) vector meaning, I can use (itr.getvalue()) but i don't have the size of the vector I'm iterating on, is there a way to make a while loop and know the end or the vector by iterator means?
If you don't have the vector for its size, and you don't have the vector's end iterator then, no, you can't. You can't reliably iterate over anything with just one iterator; you need a pair or a distance.
Others have already covered number 1. For number 2, it basically comes down to a question of what you're willing to call an iterator. It's certainly possible to define a class that will do roughly what you're asking for -- a single object that both represents a current position and has some way of figuring out when it's been incremented as much as possible.
Most people would call that something like a range rather than an iterator though. You'd have to use it somewhat differently from a normal iterator. Most iterators are used by explicitly comparing them to another iterator representing the end of the range. In this case, you'd pass two separate positions when you created the "iterator" (one for the beginning/current position, the other for the end position) and you'd overload operator bool (for the most obvious choice) to indicate whether the current position had been incremented past the end. You'd use it something like: while (*my_iterator++) operator_on(*my_iterator); -- quite a bit different from using a normal iterator.
I wish to have a const iterator for my object vector that will have
juice for the first object
typedef std::vector<Drink> Drinks;
Drinks drinks;
drinks.push_back("water");
drinks.push_back("juice");
drinks.push_back("milk");
drinks.push_back("vodka");
Drinks::const_iterator i = drinks.begin();
const iterator (itr) to a unknown (but accessible) vector
Drinks::const_iterator itr = some_func();
while (itr != drinks.end()) {
doStuff;
++itr;
}