user3677061
user3677061

Reputation: 65

exception: std::bad_alloc at memory location 0x00e4df90

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

Answers (1)

Praetorian
Praetorian

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;
}

Live demo

Upvotes: 3

Related Questions