I want to use the BOOST_FOREACH macro to iterate over a bunch of values in a vector of mine. The vector looks like this:
struct _Element
{
int key;
// more variables here
}
elements = new std::vector<_Element *>;
I'm very new to C++, and I'm a bit stumped as to how I would actually iterate over the contained _Element *'s. Why doesn't this work?
BOOST_FOREACH(_Element *currentElem, rootElement->_document->elements)
{
// do stuff
}
Compiling this gives me an error:
shared.cc:146:37: error: no viable conversion from 'std::__1::vector<_Element *, std::__1::allocator<_Element *> >' to '_Element *'
BOOST_FOREACH(_Element *currentElem, rootElement->_document->elements)
~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The type of elements is vector<_Element *>*, so you need to dereference it before passing it to BOOST_FOREACH.
BOOST_FOREACH(_Element *currentElem, *(rootElement->_document->elements))
{
// do stuff
}
That will fix the compilation error, but since you're new to C++, there's a very good chance you don't need all those pointers you've declared. For instance, your code should probably look like this:
struct Element // do not use leading underscore followed by
// uppercase letter, that's reserved
{
int key;
// more variables here
};
std::vector<Element> elements = std::vector<Element>;
// vector of Element, not Element*. And elements is a vector, not vector *
Finally, if you have a compiler that supports C++11's range based for you don't need BOOST_FOREACH.
for(auto&& currentElem : rootElement.document.elements)
// notice that I've gotten rid of all the pointers within rootElement
{
// currentElem is a reference to the current element in the elements vector
}
The statement
elements = new std::vector<_Element *>;
indicates that elements is of pointer type.
Technically that means that you need to dereference it, *elements, for use with BOOST_FOREACH.
But that's still wholly wrong on the level of good programming practice.
Instead:
Let elements just be a vector, directly. Not a pointer.
Don't use new.
Use a C++11 range-based for if your compiler supports it. If not, then upgrade your compiler and use a C++11 range-based for.
It can look like this:
for( auto const& item : elements )
{
// Do whatever
}
or if the items are of small/simple enough type that a bit of value copying doesn't matter, just
for( auto const item : elements )
{
// Do whatever
}
In passing: in addition to avoiding needless huge library dependencies, and avoiding use of raw pointers where practical, you might want to reconsider using a prefix underscore as a member name convention. Prefix underscores are used by a lot of other software and are reserved in the global namespace. A nice alternative is a suffix underscore.
BOOST_FOREACH expects a container not a pointer to a container as the second argument.
Use
BOOST_FOREACH(_Element *currentElem, *(rootElement->_document->elements))
{
// do stuff
}
Do :
BOOST_FOREACH(_Element *currentElem, *(rootElement->_document->elements))
{
.....
}
Or if your compiler supports C++11, prefer using the built-in range iteration:
for(auto element : *(rootElement->_document->elements))
{
....
}
Related
I want to erase by value from a vector of shared ptr of string (i.e vector<shared_ptr<string>>) . Is there any efficient way of doing this instead of iterating the complete vector and then erasing from the iterator positions.
#include <bits/stdc++.h>
using namespace std;
int main()
{
vector<shared_ptr<string>> v;
v.push_back(make_shared<string>("aaa"));
int j = 0,ind;
for(auto i : v) {
if((*i)=="aaa"){
ind = j;
}
j++;
}
v.erase(v.begin()+ind);
}
Also I dont want to use memory for a map ( value vs address).
Try like that (Erase-Remove Idiom):
string s = "aaa";
auto cmp = [s](const shared_ptr<string> &p) { return s == *p; };
v.erase(std::remove_if(v.begin(), v.end(), cmp), v.end());
There is no better way then O(N) - you have to find the object in a vector, and you have to iterate the vector once to find it. Does not really matter if it is a pointer or any object.
The only way to do better is to use a different data structure, which provides O(1) finding/removal. A set is the first thing that comes to mind, but that would indicate your pointers are unique. A second option would be a map, such that multiple pointers pointing to the same value exist at the same hash key.
If you do not want to use a different structure, then you are out of luck. You could have an additional structure hashing the pointers, if you want to retain the vector but also have O(1) access.
For example if you do use a set, and define a proper key - hasher or key_equal. probably hasher is enough defined as the hash for *elementInSet, so each pointer must point to a distinct string for example:
struct myPtrHash {
size_t operator()(const std::shared_ptr<std::string>& p) const {
//Maybe we want to add checks/throw a more meaningful error if p is invalid?
return std::hash<std::string>()(*p);
}
};
such that your set is:
std::unordered_set<std::shared_ptr<std::string>,myPtrHash > pointerSet;
Then erasing would be O(1) simply as:
std::shared_ptr<std::string> toErase = make_shared("aaa");
pointerSet.erase(toErase)
That said, if you must use a vector a more idomatic way to do this is to use remove_if instead of iterating yourself - this will not improve time complexity though, just better practice.
Don't include bits/stdc++.h, and since you're iterating through the hole vector, you should be using std::for_each with a lambda.
In C, it is easy to do something like:
int foo (int arr[], int size) {
// Do some stuff.
// Recur ignoring half of the input array.
return foo (arr + size / 2, size / 2);
}
I know that we are able to do that because in C, the name of array is basically a pointer to a contiguous block in the memory and basic pointer arithmetic works just fine with it.
My question is that how do I achieve this kind of convenience with C++ vector or array containers? Are there any alternative trick to do just that, fundamentally?
From what I know, this wouldn't work at all:
int foo (vector<int>& arr, int size) {
// Do some stuff.
// Recur ignoring half of the input array.
return foo (arr + size / 2, size / 2);
}
If you can't change the function signature than you can pass the vector's data() and size() properties, which are compatible with the function:
foo(v.data(), v.size());
The C++ solution is to think in terms of the objects you are using. A vector
So, you could simply use an iterator and do things like:
arr.begin()
arr.begin()+(size/2)
In other words: instead of pushing the C concept onto C++ use the corresponding C++ concept.
In this case, you can use iterators to make "parts" of your array "available" to the outside worlds.
Since you're working with a std::vector<int>, the obvious answer is not to change the function at all.
Simply call it differently.
foo(&some_vector[0], some_vector.size()); // assume some_vector is not const
This will pass a pointer to the first element and the size of some_vector to your C-style foo(). Since elements of a std::vector are guaranteed to be contiguous, this will work as you request.
Personally, however, I wouldn't do that. I'd use iterators
#include <iterator>
int foo (std::vector<int>::iterator begin, std::vector<int>::iterator end)
{
// Do some stuff.
// Recur ignoring half of the input array.
std::advance(begin, std::distance(begin, end)/2);
return foo (begin, end);
}
// to call it
foo(some_vector.begin(), some_vector.end());
You obviously need some logic to avoid infinite recursion in the function. But that is true of the function you started with.
Templates allow this to me made both simpler and more general, since it is not necessary to hard-code assumptions about the iterators (or what type of container they come from)
#include <iterator>
template<class Iterator>
int foo (Iterator begin, Iterator end)
{
// Do some stuff.
// Recur ignoring half of the input array.
std::advance(begin, std::distance(begin, end)/2);
return foo (begin, end);
}
// call like before
The requirements of std::advance() and std::distance() are pretty minimal - essentially that the iterators are what the standard calls input iterators (which means that they can be used in sequential input operations, where each value pointed by the iterator is read only once and then the iterator is incremented). Your "Do some stuff" code might introduce more restrictive requirements though.
I have a working program that capitalizes strings in a vector, using iterators:
vector<string> v7{ 10, "apples" };
for (auto vIterator= v7.begin(); vIterator!= v7.end(); ++vIterator){
auto word = *vIterator; //here
auto charIterator = word.begin();
*charIterator = toupper(*charIterator);
*vIterator = word; //also here, i guess i could just print `word` instead?
cout << *vIterator << endl;
}
My question is;
2nd line inside the loop # the comment, i had to save the pointer to the iterator to another string variable before i was able to iterate over it.
Iterating over the pointer like so
*vIterator.begin();
didn't seem to work.
Is this the correct practice, or am i missing something?
I'm new to the C languages, the concept behind pointer-like tools is quite hard to understand even if i can use them, and in this case it just feels like I'm doing it wrong.
Edit: It was a syntax error (*vIterator).begin();
It just didn't make sense why i'd have to save it to another variable before iterating over it, cheers.
Since you are using C++11 look how simpler your code can become using ranged loops like the example below:
std::vector<std::string> v(10, "apples");
for(auto &&word : v) {
word[0] = toupper(word[0]);
}
LIVE DEMO
Now as far as it concerns the (*vIterator.begin(); didn't seem to work.):
The dot operator (i.e., .) has a higher precedence than the dereference operator (i.e., *). Thus, *vIterator.begin() is interpreted as *(vIterator.begin()). The compiler rightfully complains because vIterator hasn't got a member begin().
Think of iterators as if they were pointers. The correct way to access the members of an object via a pointer/iterator pointing to it is either using the arrow operator (i.e., vIterator->begin()) or first dereference the pointer/iterator and then use the dot operator (i.e., (*vIterator).begin()).
So your code via the use of iterators would become:
std::vector<std::string> v(10, "apples");
for(auto it(v.begin()), ite(v.end()); it != ite; ++it) {
*(it->begin()) = toupper(*(it->begin()));
}
LIVE DEMO
The correct way to write *vIterator.begin(); is (*vIterator).begin(); or, more often, vIterator->begin();. Also note that you can also access the first character of a string directly (without having to iterate over it) as word[0].
A simple STL-ish way of doing it:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
vector<string> v7{ 10, "apples" };
for_each(v7.begin(), v7.end(), [](string& word){word[0] = toupper(word[0]);});
}
Is there a way for an iterator to return an object in each element of a C++ Standard Library vector?
I have this code:
struct mystruct {
int field1;
}
int DoSomethingWithMyStruct(mystruct& a);
std::vector<mystruct> myVector;
std::vector<mystruct>::iterator it;
mystruct s1,s2, temp;
s1.field1=1;
s2.field1=2;
for (it=myVector.begin();it!=myVector.end();it++)
{
//I want to call DoSomethingWithMyStruct, so I have to pass in mystruct object.
//can I use iterator to get the object of each element in myVector without having to create a temporary mystruct object and pass it in?
//I'm looking for an easier way than having to do this:
temp.field1 = it->field1;
DoSomethingWithMyStruct(temp);
}
As well as what the others said, you can do this instead:
#include <algorithm>
std::for_each(myVector.begin(), myVector.end(), DoSomethingWithMyStruct);
It's short and succinct. No need of manual loop.
Yes:
DoSomethingWithMyStruct(*it);
Just dereference the iterator, surely:
std::vector<mystruct>::iterator it, end;
for (it = myVector.begin(), end = myVector.end(); it != end; ++it) {
DoSomethingWithMyStruct(*it);
}
Or am I missing something here...?
Going further, there are other ways to iterate. You could use BOOST_FOREACH or C++0x ranged-for to simplify the loop. You could also use an algorithm like std::for_each to remove it entirely!
(Remember that it->field1 is like (*it).field1, so you're already doing this... even though you're going on to make your code more complicated than is necessary afterwards!)
Just simply dereference your iterator. *it, and you get a mystruct. They behave like pointers in this regard.
But in the case if you wonder how to iterate over all fields of all elements of a vector, where the elements are polymorphic; e.g. std::vector<Base*>, it's a bit more difficult. Since C++ doesn't have reflection that would make this possible (semi)automatically, you need to do it manually. Something similar to the Visitor Pattern comes to mind.
You have not populated myVector
Could make code more efficent like this
std::vector<mystruct>::const_iterator theEnd;
for (it=myVector.begin();it!=theEnd;++it)
Notice the position of the ++
I think that &(*it) should work.
I have a requirement to create two different maps in C++. The Key is of type CHAR* and the Value is a pointer to a struct. I am filling 2 maps with these pairs, in separate iterations. After creating both maps I need find all such instances in which the value of the string referenced by the CHAR* are same.
For this I am using the following code :
typedef struct _STRUCTTYPE
{
..
} STRUCTTYPE, *PSTRUCTTYPE;
typedef pair <CHAR *,PSTRUCTTYPE> kvpair;
..
CHAR *xyz;
PSTRUCTTYPE abc;
// after filling the information;
Map.insert (kvpair(xyz,abc));
// the above is repeated x times for the first map, and y times for the second map.
// after both are filled out;
std::map<CHAR *, PSTRUCTTYPE>::iterator Iter,findIter;
for (Iter=iteratedMap->begin();Iter!=iteratedMap->end();mapIterator++)
{
char *key = Iter->first;
printf("%s\n",key);
findIter=otherMap->find(key);
//printf("%u",findIter->second);
if (findIter!=otherMap->end())
{
printf("Match!\n");
}
}
The above code does not show any match, although the list of keys in both maps show obvious matches. My understanding is that the equals operator for CHAR * just equates the memory address of the pointers.
My question is, what should i do to alter the equals operator for this type of key or could I use a different datatype for the string?
My understanding is that the equals operator for CHAR* just equates the memory address of the pointers.
Your understanding is correct.
The easiest thing to do would be to use std::string as the key. That way you get comparisons for the actual string value working without much effort:
std::map<std::string, PSTRUCTTYPE> m;
PSTRUCTTYPE s = bar();
m.insert(std::make_pair("foo", s));
if(m.find("foo") != m.end()) {
// works now
}
Note that you might leak memory for your structs if you don't always delete them manually. If you can't store by value, consider using smart pointers instead.
Depending on your usecase, you don't have to neccessarily store pointers to the structs:
std::map<std::string, STRUCTTYPE> m;
m.insert(std::make_pair("foo", STRUCTTYPE(whatever)));
A final note: typedefing structs the way you are doing it is a C-ism, in C++ the following is sufficient:
typedef struct STRUCTTYPE {
// ...
} *PSTRUCTTYPE;
If you use std::string instead of char * there are more convenient comparison functions you can use. Also, instead of writing your own key matching code, you can use the STL set_intersection algorithm (see here for more details) to find the shared elements in two sorted containers (std::map is of course sorted). Here is an example
typedef map<std::string, STRUCTTYPE *> ExampleMap;
ExampleMap inputMap1, inputMap2, matchedMap;
// Insert elements to input maps
inputMap1.insert(...);
// Put common elements of inputMap1 and inputMap2 into matchedMap
std::set_intersection(inputMap1.begin(), inputMap1.end(), inputMap2.begin(), inputMap2.end(), matchedMap.begin());
for(ExampleMap::iterator iter = matchedMap.begin(); iter != matchedMap.end(); ++iter)
{
// Do things with matched elements
std::cout << iter->first << endl;
}