简体   繁体   中英

Freeing Memory Allocation

I'm having trouble figuring out what this error means exactly. It says:

map-test(29262,0x7fffb118e340) malloc: *** error for object 0x7fa5d7001000: pointer being freed was not allocated

However, I'm pretty sure that it was allocated. Here are the functions in question. I guess that it could be possible that I messed up the memory somewhere, but I don't think that's the case, but then again I'm new at some of this stuff and my professor loves pointers religiously (sadly). Can someone steer me in the right direction? Many thanks in advance.

map.cpp

#include "map.hpp"
#include <string>
#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include <iostream>

Map::Map() {
    database = new MapEntry*[DATABASE_SIZE];
    for (int i = 0; i < DATABASE_SIZE; i++){
        database[i] = new MapEntry("", 0);
    }
}

/* Adds (inserts) val with the associated key.
 * Returns if successful or not.  (It is not successful if we are out of
 * memory, or if the key already exists.)
 */
bool Map::add(const char *key, int val) {
    for (int i = 0; i < DATABASE_SIZE; i++)
        if (database[i]->getVal() == 0) {
            database[i]->setVal(val);
            database[i]->setKey(key);
            return true;
        }
    return false;
}

/* Searches for the key.  If found it sets ret to the correct val and
 * returns true.  Otherwise this function returns false.
 */
bool Map::get(const char *key, int &ret) {
    for (int i = 0; i < DATABASE_SIZE; i++){
        if (database[i]->getKey() == key) {
            ret = database[i]->getVal();
            return true;
        }
    }
    return false;
}

/* Returns the size (memory consumed) by this data structure. */
int Map::size() {
    int totalsize = 0;
    for (int i = 0; i < DATABASE_SIZE; i++){
        if (database[i]->getVal() != 0) {
            totalsize += sizeof(database[i]);
        }
    }
    return totalsize;
}

/* Removes the current value from the Map AND frees up any memory that it can.
 * Returns true if there was something to remove, false otherwise.
 */
bool Map::remove(const char *key) {
    for (int i = 0; i < DATABASE_SIZE; i++){
        if (database[i]->getKey() == key) {
            database[i]->setKey("");
            database[i]->setVal(0);
            return true;
        }
    }
    return false;
}

/* Returns the number of names with a given prefix.
 * EX: If we have {John, Jonathan, Paul, Mark, Luke, Joanna} then
 * howMany("Jo") == 3
 */
int Map::howMany(const char *prefix) {
    int count = 0;
    std::string beginning(prefix);
    for (int i = 0; i < DATABASE_SIZE; i++){
        std::string key(database[i]->getKey());
        if (key.substr(0, beginning.size()).compare(beginning) == 0) {
            count++;
        }
    }
    return count;
}

/* Frees all memory */
Map::~Map() {
for (int i = 0; i < DATABASE_SIZE; i++) {
        delete database[i];
    }
    delete[] database;
}

map.hpp

#ifndef MAP_H
#define MAP_H

const int DATABASE_SIZE = 1024;

class MapEntry{
    private:
        int mIDVal;
        const char* mKeyName;

    public:
        MapEntry(const char *key, int val) {
        mKeyName = key;
        mIDVal = val;
    }
    int getVal(){
        return mIDVal;
    }
    const char* getKey(){
        return mKeyName;
    }
    void setVal(int val){
        mIDVal = val;
    }
    void const setKey(const char* key){
        mKeyName = key;
    }
};

class Map{
    public:
        Map();

        bool add(const char *key, int val);

        void print();

        bool get(const char *key, int &ret);

        int size();

        bool remove(const char *key);

        int howMany(const char *prefix);

    ~Map();
private:
    MapEntry **database;
    Map(const Map &m){
        // Copy constructor in private to avoid double deleting.
    }
};

#endif

main.cpp

#include <stdlib.h>
#include <iostream>
#include "map.hpp"

using namespace std;

int main(int argc, char *argv[]) {
    Map myMap;
    myMap.add("Philip Fry", 51798);
    myMap.add("Turanga Leela", 987651234);
    myMap.add("Philip Fry", 89715);
    int pringles = 0;
    myMap.get("Philip Fry", pringles);
    cout << pringles << "\n";
    myMap.print();
    cout << myMap.size() << "\n";
    cout << "\n";
    myMap.remove("Philip Fry");
    myMap.print();
    pringles = 0;
    myMap.get("Philip Fry", pringles);
    cout << pringles << "\n";
    const char* prefix = "Phi";
    cout << myMap.howMany(prefix) << "\n";

    myMap.~Map();
    return 0;
}

You are double free-ing the memory right here when you are calling the destructor directly. You are not supposed to call the destructor manually. It is automatically called when objects go out of scope. There is your double delete.

myMap.~Map();  ///< this is wrong (get rid of it)

If you want visual evidence that the destructor is getting invoked twice, then modify it to print.

/* Frees all memory */
Map::~Map() {
    std::cout << "Map::~Map() invoked!" << std::endl;
    for (int i = 0; i < DATABASE_SIZE; i++) {
        delete database[i];
    }
    delete[] database;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM