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);
}
Related
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?
I've got a bit of a conundrum here. I am writing a mesh (grid) generator. In doing so, I need to obtain a list of lower dimensional elements from higher dimensional elements (i.e. a "triangle" element is composed of 3 "line" elements). I need the list of unique line elements and I need the parent element to store a pointer to each of its unique child elements.
To this end, I create a std::set of smart pointers to the child elements and try to insert each child element to the list. Every time I try to insert an element I ask for a pair containing an iterator to the pre-existing element and a boolean specifying whether or not the element has been inserted.
The problem is that std::set (and map) return constant iterators to the pre-existing element. However, I need to give the parent element of the element that I failed to insert a non-constant pointer to the pre-existing element. So I use const_pointer_cast<> to cast the constant iterator to a non-constant one.
Is there a better way of going about this? Doing a const_pointer_cast() is probably not ideal. Is there something that I should be using for this application instead of std::set?
Edit: here's the function:
template<class T1, class T2>
int getUniqueSubelements(std::set<std::shared_ptr<T1>, elGreater>& elements,
std::set<std::shared_ptr<T2>, elGreater>& childels)
{
typedef std::shared_ptr<T2> child_ptr;
std::pair<typename std::set<child_ptr, elGreater>::iterator, bool> ret;
for (auto parit = elements.begin(); parit != elements.end(); ++parit)
{
(*parit)->generateChildren();
const std::vector<child_ptr>& children = (*parit)->getChildren();
for (int i = 0; i < children.size(); i++)
{
ret = childels.insert(children[i]);
if (ret.second == false)
{
child_ptr temp = std::const_pointer_cast<T2>(*ret.first);
bool orient = elOrientation(children[i], temp);
children[i]->swapInParent(temp, orient);
}
}
}
return 1;
}
No cast at all is needed here.
It's true that std::set<K, Comp>::iterator is the same as std::set<K, Comp>::const_iterator, and that iterator::operator* returns a const K&.
But in your case, this means that the type of *ret.first is const std::shared_ptr<T2>&. This is the analogue of (T2* const), not (const T2*): you can't modify the smart pointer, but you can modify the actual stored object.
So assuming elOrientation is something like
template <typename T>
bool elOrientation(std::shared_ptr<T>, std::shared_ptr<T>);
you can just call elOrientation(children[i], *ret.first).
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;
}
I'm lost: An iterator of a vector of std::string works perfectly unless there is a function call (Z_UB->set() ) before it++. Here's the code:
std::vector< std::string >::iterator it = g_SPP.scenarios->getVector().begin();
std::cout << "begin of vector: " << *it << std::endl;
Z_UB->set("s1", "scn2", 350);
it++;
std::cout << "second of vector: " << *it << std::endl;
creates the following output
begin of vector: scn1
However, if I move the function call like this:
std::vector< std::string >::iterator it = g_SPP.scenarios->getVector().begin();
std::cout << "begin of vector: " << *it << std::endl;
it++;
std::cout << "second of vector: " << *it << std::endl;
Z_UB->set("s1", "scn2", 350);
The result is the following, which is the expected behaviour:
begin of vector: scn1
second of vector: scn2
Inside the Z_UB->set() function there is nothing left but the call itself:
void Parameter::set( std::string _i, std::string _j, float value) {
//int i = indexSets[0]->backIndex(_i);
//int j = indexSets[1]->backIndex(_j);
//data2D[0][0] = value;
}
So if I call the Z_UB->set() function after I created the iterator, accessing it will crash the program. Is there anything vital that I missed about Iterators?
Several possibilities:
Either you do not have a good reproductible example: maybe in your first run you had only one element in your vector (how is it filled?), and invoked undefined behaviour because you did not check it against g_SPP.scenarios->getVector().end()
Or Z_UB->set does not do what you think. Is it a polymorphic class? Is set virtual? Is the -> operator overloaded?
Is your app multithreaded and another thread is mutating your container?
If g_SPP is a global variable then iterators over it will be invalidated by any mutating operation.
Update -- this is from the 1998 ISO/ANSI spec:
The following invalidate all references, iterators, and pointers referring to elements of the sequence if an allocation is required. An allocation is required if the current capacity() is less than the target vector size.
void reserve(size_type n)
iterator insert(iterator position, const T& x),
void insert(iterator position, size_type n, const T& x),
void insert(iterator position, InputIterator first, InputIterator last), and
Erasure invalidates all references, iterators, and pointers referring to elements after the position of the initial erased element.
iterator erase(iterator position)
iterator erase(iterator first, iterator second)
Resizing a vector is equivalent to calling either insert or erase. According to 23.2.4.2/6: resize(sz, c=value_type()) has the same effect as:
if (sz > size())
insert(end(), sz - size(), c);
else if (sz < size())
erase(begin() + sz, end());
else
;
a std::vector<T>::iterator will be invalidated if you add or remove elements while iterating over it, if the vector needs to resize itself internally, when an element is added.
.getVector() returned a copy of the vector. Comparing an iterator to the end point of the iterator of a completely different object doesn't make sense. Returning a reference solved the problem.
#Xeo also pointed out a much better explanation: When creating an iterator from a copy like this:
std::vector< std::string >::iterator it = g_SPP.scenarios->getVector().begin();
the copy immediately is destroyed thus invalidating the just created iterator. So the iterator shouldn't have returned the first element in the first place, but I can merely guess that this is hidden deeply in the implementation of the compiler.
I'm very use to working with arrays and vectors, but now I'm playing with some STD::lists, as well as a custom list class I made.
Let's say I have a simple class, Stock.
//stock.h
class Stock{
public:
Stock(); //default constructor
Stock(string, double); //overloaded constructor
void setSymbol(string); //sets stock symbol
void setPrice(double);
string getSymbol();
double getPrice();
private:
string symbol;
double price;
};
Now in a separate file I have my int main to test.
#include "stock.h"
#include <list>
int main(){
list<Stock> portfolio;
Stock Google("GOOG", 500);
Stock Apple("APPL", 300);
Stock Chipotle("CMG", 200);
portfolio.push_back(Google);
portfolio.push_back(Apple);
portfolio.push_back(Chipotle);
}
Now if this was a vector or array, I would have no problem, I'm just completely loss on the linked-list equivalent of the following:
for(int i=0; i <portfolio.size(); i++){
portfolio[i].getSymbol();
portfolio[i].getPrice();
}
Or something along those lines...I have no lecture/training in Linked-Lists so I'm really trying to do my best in teaching myself--but I'm stuck on basic manipulation. I'm using STL::list right now, but really trying to make my own class as well.
for(int i= portfolio.begin(); i <portfolio.size(); i++)
If this worked for a std::vector, it was only by sheer accident. I have no idea how that might have worked for a vector.
std::any_stl_container::begin() returns an object called an "iterator". Specifically, an object of type std::any_stl_container::iterator. An iterator is kind of like a generalized pointer: it refers to an element in an STL container.
The iterator returned by begin is the iterator that references the first element in the list. You can move iterators around like pointers. For example:
std::list<Stock> portfolio;
...
std::list<Stock>::iterator currElem = portfolio.begin();
++currElem; //Now points to the second element in the list.
Stock &secondStock = *currElem;
In order to iterate over all of the elements in a list, you need two iterators: the first one, and the iterator for the element after the last element in the list. Fortunately, this is returned by the std::any_stl_container::end() function. So, your loop should look like:
typedef std::list<Stock>::iterator StockIt;
for(StockIt i = portfolio.begin(); i != portfolio.end(); ++i) /* Prefer pre-increment with iterators */
{
i->getSymbol();
i->getPrice();
}
This will work for any of the usual STL containers.
You have iterators as begin() and end() for std::list also:
for (list<stock>::iterator it = portfolio.begin() ; it != portfolio.end(); it++)
{
// use 'it' to access the current element (i.e. *it)
}
You have to use iterators. Every STL container has them, even vector. They behave similarly to pointers; they can be dereferenced with * or ->, they can be incremented, they can be compared.
for( list<Stock>::iterator it = portfolio.begin(); it != portfolio.end(); it++ ){
it->getSymbol();
it->getPrice();
}
An object of type std::list is very inefficient if you try to compute its length, because such an operation would have linear time.
Therefore with lists, you cannot compare iterators with the < and > operators. It is also ill-advised to try to get the nth element with the operator [].
Also, you should not mix begin() and size() which are respectively an iterator and an integer.
The proper way to iterate over an std::list is to use the pair of iterators begin() and end() and to increment your iterator until it reaches the end().
So, two ways:
for(std::list<stock>::const_iterator i = my_list.cbegin(); i != my_list.cend(); ++i)
{
// access a “const stock &” object via *i
}
or
for(std.:list<stock>::iterator i = my_list.begin(); i != my_list.end(); ++i)
{
// access a “stock &” object via *i
}