Reputation: 65
I'm trying to build a function that takes a string and vector containing objects of a custom class as arguments and returns the element of the vector that has the same .name string member as the argument string. The function that I've written is as follows and works as long as I don't try to use the ingame "get object" feature on an item that doesn't exist. If I do that the program crashes with the run time error in the title. I'm not sure what is causing this error, could someone point out the mistake? I've tried making sure all the paths in string_to_item return an items type but that didn't work. Another interesting thing is that break never actually causes the for loop to stop, it just continues to the end.
items string_to_item( string item_name, const vector<items>& item_container ) {
if ( item_container.size() > 0 ) {
for (int i = 0; i < item_container.size(); ++i) {
if ( item_container[i].name == item_name ) {
return item_container[i];
break;
}
else
cout << "No such item found";
}
}
else
return items("null");
if ( item_container.size() == 0)
cout << "no elements in vector ( get_item )";
}
The debugger call stack points to this at the time of the crash:
KernelBase.dll!74b01d4d()
The other functions that calls this function and the class involved are:
void get(const vector<string>& input_tokens, vector<items>& global_item_list) {
player_inventory.get_item( string_to_item( input_tokens[1], global_item_list) );
cout << "You have picked up a " << input_tokens[1] << ".\n\n";
remove_from_world( string_to_item( input_tokens[1], global_item_list), global_item_list);
}
void inventory::get_item( items name ) {
contents.push_back(name);
}
struct items {
string name;
char type;
string description;
items() {
name = " ";
type = ' ';
description = " ";
}
items( string n )
: name(n) {}
items( string n, char t, string d )
: name(n), type(t), description(d) {}
bool operator()( const items& one, const items& two ) const {
return one.name.compare(two.name) < 0;
}
};
void remove_from_world( items full_def, vector<items>& global_item_list ) {
vector<items>::iterator it = find( global_item_list.begin(), global_item_list.end(),full_def);
int i = distance(global_item_list.begin(), it);
if (it != global_item_list.end())
global_item_list.erase(global_item_list.begin() + i);
else {
cout << "remove from world failure";
return;
}
}
Thanks.
Upvotes: 1
Views: 1747
Reputation: 109189
I'm not debugging your code since you shouldn't be writing loops like that for something as simple as locating an item in a container. Use an algorithm from <algorithm>
and your problem will most likely disappear.
Since you're looking for an items
object with a particular name
, you need to use std::find_if
. The predicate you supply will do the job of comparing item_name
to items::name
.
With C++11 this is extremely easy, write a lambda expression that does the job.
items string_to_item( string item_name, const vector<items>& item_container )
{
auto result = std::find_if(item_container.begin(), item_container.end(),
[&](items const& it) {
return it.name == item_name;
});
if(result == item_container.end()) {
if(item_container.size() == 0) {
std::cout << "no elements in vector ( get_item )";
}
return items("null");
}
return *result;
}
If you're using an older compiler, then the task becomes a bit more verbose. The easiest option is to create a functor that stores a reference to item_name
and overloads operator()
to perform the comparison. This is exactly what the compiler is doing behind the scenes in the C++11 version above.
struct comparer
{
comparer(std::string const& item_name) : item_name(item_name) {}
bool operator()(items const& it) const { return it.name == item_name; }
std::string const& item_name;
};
items string_to_item( string item_name, const vector<items>& item_container )
{
comparer comp(item_name);
std::vector<items>::const_iterator result =
std::find_if(item_container.begin(), item_container.end(), comp);
if(result == item_container.end()) {
if(item_container.size() == 0) {
std::cout << "no elements in vector ( get_item )";
}
return items("null");
}
return *result;
}
Upvotes: 3