I don't really have a very good understanding to how STL works.
I was able to create a list and add items to it.
But now I can't seem to search through the list to find an element with a desired property.
Forgive my ignorance on this. I am very new to STL and I still struggle with some elements of C++.
Here is the code. I know it produces errors , but I would like something like this.
Thanks in advance.
extern list<MonsterClass> Monsters;
MonsterClass FindMonster(int x)
{
MonsterClass Monster;
list<MonsterClass>::iterator ListItem;
for(ListItem = Monsters.begin(); ListItem != Monsters.end(); ++ListItem)
{
if (ListItem.X == x)
{
Monster = ListItem;
return Monster;
}
}
return NULL;
}
You are confusing elements and iterators. Iterators are placeholders for positions in the list, they are not the elements themselves. To get to the element, you need to dereference an iterator:
if ((*ListItem).X == x) // or, easier: if(ListItem->X == x)
{
Monster = *ListItem;
return Monster;
}
}
Furthermore, you cannot return NULL since your Monster class cannot take the value NULL (which is a pointer). What you can do is return an iterator instead of the item itself. Then your function does almost exactly the same as the std::find function from the <algorithm> standard header.
// C++03
struct by_X {
by_X( int x ) : x(x) {}
bool operator()( Monster const & m ) const {
return x == m.X;
}
const int x;
};
std::find_if( Monsters.begin(), Monsters.end(), by_X( 5 ) );
If your compiler has lambda (c++0x) support:
std::find_if( Monsters.begin(), Monsters.end(), [=x]( Monster const & m ) { return m.X == x; } );
If you want to do this very often (like, unless it's just for debugging or something like that), a list probably isn't the best choice for the job. Just for one obvious alternative, a std::set directly supports searching like this. In a set the search will normally be quite a bit faster as well (logarithmic instead of linear complexity).
Related
I want to have in a google protocol buffer repeated field only unique elements. In other words, need to use it as a std::set instead of std::vector.
Any idea which is the simplest and most efficient way to do that?
EDIT: I wouldn't want to use any iterators to loop through all the elements if possible.
Ok, as the comments from the question stated, there isn't any way of doing this without using iterators.
However, maybe someone else is interested in this, here is the function i coded to achieve this. This will take as parameters a RepeatedPtrField< T >*(the list) and a std::string(key of the new object that we intend to add to the list) and will return the element that matches the id, or NULL if there isn't any entry with this key in the RepeatedField list.
This way, you can easy keep a list of unique elements directly in a RepeatedField without using any other std structure:
template <class T>
T* repeatedFieldLookup( google::protobuf::RepeatedPtrField< T >* repeatedPtrField, std::string id)
{
google::protobuf::internal::RepeatedPtrOverPtrsIterator<T> it = repeatedPtrField->pointer_begin();
for ( ; it != repeatedPtrField->pointer_end() ; ++it )
{
CommonFields * commonMessage = (CommonFields*) (*it)->GetReflection()->
MutableMessage ((*it), (*it)->GetDescriptor()->FindFieldByName ("common"));
if(commonMessage->id() == id)
{
return *it;
}
}
return NULL;
}
NOTE: in the example above, the proto message will ALWAYS have a field called common(which in my case is also a proto message). You can replace that by anything that you want to make the comparison from your proto messages.
In the case where I had this class:
class Description : public ::google::protobuf::Message {
// ...
inline void add_field(const ::std::string& value);
inline const ::google::protobuf::RepeatedPtrField< ::std::string>& field() const;
// ...
};
I used std::find to only add a value if it didn't exist in the list:
#include <algorithm>
void addField(Description& description, const std::string& value) {
const auto& fields = description.field();
if (std::find(fields.begin(), fields.end(), value) == fields.end()) {
description.add_field(value);
}
}
How do I get the position of an element inside a vector, where the elements are classes. Is there a way of doing this?
Example code:
class Object
{
public:
void Destroy()
{
// run some code to get remove self from vector
}
}
In main.cpp:
std::vector<Object> objects;
objects.push_back( <some instances of Object> );
// Some more code pushing back some more stuff
int n = 20;
objects.at(n).Destroy(); // Assuming I pushed back 20 items or more
So I guess I want to be able to write a method or something which is a member of the class which will return the location of itself inside the vector... Is this possible?
EDIT:
Due to confusion, I should explain better.
void Destroy(std::vector<Object>& container){
container.erase( ?...? );
}
The problem is, how can I find the number to do the erasing...? Apparently this isn't possible... I thought it might not be...
You can use std::find to find elements in vector (providing you implement a comparison operator (==) for Object. However, 2 big concerns:
If you need to find elements in a container then you will ger much better performance with using an ordered container such as std::map or std::set (find operations in O(log(N)) vs O(N)
Object should not be the one responsible of removing itself from the container. Object shouldn't know or be concerned with where it is, as that breaks encapsulation. Instead, the owner of the container should concern itself ith such tasks.
The object can erase itself thusly:
void Destroy(std::vector<Object>& container);
{
container.erase(container.begin() + (this - &container[0]));
}
This will work as you expect, but it strikes me as exceptionally bad design. Members should not have knowledge of their containers. They should exist (from their own perspective) in an unidentifiable limbo. Creation and destruction should be left to their creator.
Objects in a vector don't automatically know where they are in the vector.
You could supply each object with that information, but much easier: remove the object from the vector. Its destructor is then run automatically.
Then the objects can be used also in other containers.
Example:
#include <algorithm>
#include <iostream>
#include <vector>
class object_t
{
private:
int id_;
public:
int id() const { return id_; }
~object_t() {}
explicit object_t( int const id ): id_( id ) {}
};
int main()
{
using namespace std;
vector<object_t> objects;
for( int i = 0; i <= 33; ++i )
{
objects.emplace_back( i );
}
int const n = 20;
objects.erase( objects.begin() + n );
for( auto const& o : objects )
{
cout << o.id() << ' ';
}
cout << endl;
}
If you need to destroy the n'th item in a vector then the easiest way is to get an iterator from the beginning using std::begin() and call std::advance() to advance how ever many places you want, so something like:
std::vector<Object> objects;
const size_t n = 20;
auto erase_iter = std::advance(std::begin(objects), n);
objects.erase(erase_iter);
If you want to find the index of an item in a vector then use std::find to get the iterator and call std::distance from the beginning.
So something like:
Object object_to_find;
std::vector<Object> objects;
auto object_iter = std::find(std::begin(objects), std::end(objects), object_to_find);
const size_t n = std::distance(std::begin(objects), object_iter);
This does mean that you need to implement an equality operator for your object. Or you could try something like:
auto object_iter = std::find(std::begin(objects), std::end(objects),
[&object_to_find](const Object& object) -> bool { return &object_to_find == &object; });
Although for this to work the object_to_find needs to be the one from the actual list as it is just comparing addresses.
I have my loop going through vector's elements. While in this loop some of the elements are being (I want them to be) removed. Although std::vector does not allow to do this, and I would like an alternative.
for(unsigned int j = 0; j < rectArray.size(); j++)
{
if( rectArray[j] == 2 )
{
rectArray.erase(rectArray.begin() + j);
}
//...
}
Do you think a std::list would be good here ? Can I use something else ?
Unless the elements of the vector are very expensive to copy, the simplest is probably to std::copy_if (or otherwise copy the ones you want to keep) into a new vector, and then swap that with the original. There's also remove_if followed by resize.
If the elements are very expensive to relocate, then a list would avoid that, but it depends what else you do with the collection. If you do something else that would be cripplingly slow with a list, then you've just moved the problem elsewhere.
I would suggest modifying your code such that it uses iterators instead of the actual vector. It's much cleaner and more efficient like this:
for (auto it = rectArray.begin(); it != rectArray.end(); ++it)
{
// Access the current element with *it
// If you want you can pass `it` and `rectArray.end()` as
// the lower and upper bounds of the new collection,
// rather than doing expensive resizes of the vector.
}
Note that auto is a C++11 feature (the way I used it). If your compiler supports that you might also want to use C++11's foreach:
for (auto it : rectArray) {
// same as before
}
Removing an element from the middle of a vector is expensive - because you have to move all the later elements down.
If you need to add/remove elements to the middle of a container then a list is generally better.
List would be better than a vector - as it will not cost you anything to remove elements from the middle of the list. Removing elements from the middle of a vector, on the other hand, has linear complexity.
Possible alternative to std::remove_if. A bit faster and doesn't require a functor, however it does not maintain order.
auto end = std::end(rectArray);
for(auto it = std::begin(rectArray); it != end; ++it)
{
if(it->remove_me()))
std::swap(*it, *--end); // or even faster *it = std::move(*--end);
}
rectArray.erase(end, std::end(rectArray));
If you are doing a lot of deletes, a list is probably the way to go. Here is some sample code to help.
#include <vector>
#include <list>
#include <algorithm>
using namespace std;
class Widget
{
public:
explicit Widget(int someNumber);
bool ShouldDelete();
bool ShouldDeleteComplex(int a, int b, int c);
private:
int _someNumber;
};
Widget::Widget(int someNumber) : _someNumber(someNumber)
{
}
bool Widget::ShouldDelete()
{
if (_someNumber > 2)
{
return true;
}
return false;
}
bool Widget::ShouldDeleteComplex(int a, int b, int c)
{
if ((a * b - c) > _someNumber)
{
return true;
}
return false;
}
int main()
{
list<Widget> lw;
lw.push_back(Widget(1));
lw.push_back(Widget(2));
lw.push_back(Widget(3));
// delete from list using functor
lw.remove_if(mem_fun_ref(&Widget::ShouldDelete));
// delete from list using lambda function
lw.remove_if([] (Widget& x) { return x.ShouldDeleteComplex(1, 2, 0); } );
vector<Widget> vw;
vw.push_back(Widget(1));
vw.push_back(Widget(2));
vw.push_back(Widget(3));
// delete using functor
vw.erase(remove_if(vw.begin(), vw.end(), mem_fun_ref(&Widget::ShouldDelete)), vw.end());
// delete using lambda function
vw.erase(
remove_if(vw.begin(), vw.end(),
[] (Widget& x) { return x.ShouldDeleteComplex(1, 2, 0); }
),
vw.end());
return 0;
}
I'm trying to walk through a list. Here are some declarations:
list<CG1_Edge*> ActiveEdges;
list<CG1_Edge*>::iterator ActiveEdgeIterator;
Sometimes, this code segfaults on line 2:
for (this->ActiveEdgeIterator = this->ActiveEdges.begin(); this->ActiveEdgeIterator != this->ActiveEdges.end(); ++this->ActiveEdgeIterator) {
CG1_Edge* currentEdge = *this->ActiveEdgeIterator;
if (currentEdge->y_up < y)
this->ActiveEdges.erase(this->ActiveEdgeIterator);
}
Are there any common reasons why this might result in a segfault?
You should use something like:
for (this->ActiveEdgeIterator = this->ActiveEdges.begin(); this->ActiveEdgeIterator != this->ActiveEdges.end(); ) {
CG1_Edge* currentEdge = *this->ActiveEdgeIterator;
if (currentEdge->y_up < y)
this->ActiveEdgeIterator = this->ActiveEdges.erase(this->ActiveEdgeIterator);
else
++this->ActiveEdgeIterator;
}
since erase returns an iterator positionned at the next element.
(Note: having that iterator as a member looks strange.)
Begemoth's comment should be the accepted answer. According to the standard erase invalidates "all iterator and references to elements after position"(my mistake; this was for vector and possibly other containers; so at least to avoid surprises you should do well to use the algorithm version instead).
So you'd be safer already using rbegin() and rend(). But why not use the std::alogirthms!
struct Predicate
{
int _y;
explicit Predicate(int y) : _y(y) {}
bool operator()(const CG1_Edge edge) const
{
return currentEdge->y_up < _y;
}
};
std::erase(
std::remove_if(this->ActiveEdges.begin(), this->ActiveEdges.end(), Predicate(y)),
this->ActiveEdges.end());
Example routine:
const Armature* SceneFile::findArmature(const Str& name){
for (int i = 0; i < (int)armatures.size(); i++)
if (name == armatures[i].name)
return &armatures[i];
return 0;
}
Routine's purpose is (obviously) to find a value within an array of elements, based on element's member variable, where comparing member variable with external "key" is search criteria.
One way to do it is to iterate through array in loop. Another is to use some kind of "map" class (std::map, some kind of vector sorted values + binarySearch, etc, etc). It is also possible to make a class for std::find or for std::for_each and use it to "wrap" the iteration loop.
What are other ways to do that?
I'm looking for alternative ways/techniques to extract the required element.
Ideally - I'm looking for a language construct, or a template "combo", or a programming pattern I don't know of that would collapse entire loop or entire function into one statement. Preferably using standard C++/STL features (no C++0x, until it becomes a new standard) AND without having to write additional helper classes (i.e. if helper classes exist, they should be generated from existing templates).
I.e. something like std::find where comparison is based on class member variable, and a variable is extracted using standard template function, or if variable (the one compared against "key"("name")) in example can be selected as parameter.
The purpose of the question is to discover/find language feature/programming technique I don't know yet. I suspect that there may be an applicable construct/tempalte/function/technique similar to for_each, and knowing this technique may be useful. Which is the main reason for asking.
Ideas?
If you have access to Boost or another tr1 implementation, you can use bind to do this:
const Armature * SceneFile::findArmature(const char * name) {
find_if(armatures.begin(), armatures.end(),
bind(_stricmp, name, bind(&string::c_str, bind(&Armature::name, _1))) == 0);
}
Caveat: I suspect many would admit that this is shorter, but claim it fails on the more elegant/simpler criteria.
Sure looks like a case for std::find_if -- as the predicate, you could use e.g. a suitable bind1st. I'm reluctant to say more as this smacks of homework a lot...;-).
Why 5 lines? Clean doesn't have a number attached to it. In fact, clean code might take more lines in the utility classes, which can then be reused over and over. Don't restrict yourself unnecessarily.
class by_name
{
public:
by_name(const std::string& pName) :
mName(pName)
{}
template <typename T>
bool operator()(const T& pX)
{
return pX.name == pName;
}
private:
std::string mName;
};
Then:
const Armature* SceneFile::findArmature(const char* name)
{
// whatever the iterator type name is
auto iter = std::find_if(armatures.begin(), armatures.end(), by_name(name));
return iter == armatures.end() ? 0 : &(*iter);
}
Within restriction:
class by_name { public: by_name(const std::string& pName) : mName(pName) {} template <typename T> bool operator()(const T& pX) { return pX.name == pName; } private: std::string mName; };
Then:
const Armature* SceneFile::findArmature(const char* name)
{
// whatever the iterator type name is
auto iter = std::find_if(armatures.begin(), armatures.end(), by_name(name));
return iter == armatures.end() ? 0 : &(*iter);
}
:)
C++0x has ranged-based for-loops, which I think would make the most elegant solution:
const Armature* SceneFile::findArmature(const std::string& pName) const
{
for (auto a : armatures)
{
if (a.name = pName) return &a;
}
return 0;
}
You would probably need to use STL map. It gives you possibility to get the element using keys. Your key would be the name of armature.
http://www.cplusplus.com/reference/stl/map/
EDIT: :D
one liner B-)
const Armature* SceneFile::findArmature(const Str& name){for (int i = 0; i < (int)armatures.size(); i++) if(name == armatures[i].name) return &armatures[i]; return 0;}
Holy shiz, you're using _stricmp? FAIL. Also, you didn't actually tell us the type of the vectors or any of the variables involved, so this is just guesswork.
const Armature* SceneFile::findArmature(const std::string& lols) {
for(auto it = armatures.begin(); it != armatures.end(); it++) {
if (boost::iequals(lols, (*it).name))
return &(*it);
return NULL;
}
Ultimately, if you need this, you should put the armatures or pointers to them in a std::map. A vector is the wrong container if you're searching into it, they're best for when the collection is what's important rather than any finding behaviour.
Edited to use a std::string reference.