在抛出 std::bad_alloc 的实例后调用终止。使用两个 类,一个带有指向另一个的指针

Terminate called after throwing an instance of std::bad_alloc. Using two classes, one with a pointer to the other

当我使用包含成员函数的普通函数时,我的程序总是出现错误的分配错误。

该程序是关于从命令行获取一些特定输入并打印指针数组的元素。这必须用指针数组来完成。

首先,我创建了一个需要有 2 个字符串的 class。一张是名字,一张是房间。然后我创建了另一个 class,它有一个大小和一个指向我的第一个 class 的指针,以创建一个数组。

我的main在最后,main上面是2个普通函数。这段代码有什么问题?当我第一次在循环中键入命令时,它会一直工作,直到我输入连接到正常功能的命令。可能那里有问题,但我似乎无法找到它。

#include <iostream>
#include <string>
using namespace std;

class Address
{
    private:
        string name;
        string room;
    public:
        Address(){};
        Address(string, string);
        string get_name();
        string get_room();
        void change_room(string);
};

Address::Address (string n, string r)
{
    name = n;
    room = r;
}


string Address::get_name()
{
    return name;
}

string Address::get_room()
{
    return room;
}

void Address::change_room(string change)
{
    room = change;
}


//end of Address class


class Address_Book 
{
    private:
        int size;
        Address* addresses;
    public:
        Address_Book();
        ~Address_Book(){ delete[] addresses;}
        void add(Address);
        void move(string, string);
        int get_size();
        Address location(int);
        int find(string);
        void clear();
        void remove_address(string);
        int exists(string);
        void sort();
};


Address_Book::Address_Book()
{
    int s = 0;
    size = s;
    addresses = new Address[s];
}

void Address_Book::add(Address add)
{
    Address* temp = new Address [size + 1];
    for (int i = 0; i < size; i++)
    {
        temp[i] = addresses[i];
    }
    temp[size] = add;
    delete[] addresses;
    addresses = temp;
    size ++;

}

void Address_Book::move(string name, string newroom)
{
    for (int i = 0; i < size ; i++)
    {
        if (addresses[i].get_name() == name )
        {
            addresses[i].change_room(newroom);
        }
    }
}

void Address_Book::remove_address(string name)
{
    Address* temp = new Address [size - 1];

    for (int i = 0; i < size; i++)
    {
        if (addresses[i].get_name() != name)
        {
            temp[i] = addresses[i];
        }
        else if (addresses[i].get_name() == name)
        {
            for (int j = i + 1; j < size; j++)
            {
                temp[i] = addresses[j];
                i++;
            }
            break;
        }
    }
    delete[] addresses;
    addresses = temp;
    size--;
}


int Address_Book::get_size()
{
    return size;
}


Address Address_Book::location(int index)
{
    return addresses[index];
}


void Address_Book::sort()
{
    Address temp;
    for (int i = 0; i < size; i++)
    {
        for(int j = 0; j < size - 1; j++)
        {
            if (addresses[j].get_room() > addresses[j + 1].get_room())
            {
                temp = addresses[j];
                addresses[j] = addresses[j + 1];
                addresses[j + 1] = temp;
            }
        }
    }
    for (int i = 0; i < size; i++)
    {
        if (addresses[i].get_room() == addresses[i + 1].get_room())
        {
            if (addresses[i].get_name() > addresses[i + 1].get_name())
            {
                temp = addresses[i];
                addresses[i] = addresses[i + 1];
                addresses[i + 1] = temp;
            }
        }
    }
}

void Address_Book::clear()
{
    Address * temp = new Address[0];
    delete[] addresses;
    addresses = temp;
    size = 0;
}


int Address_Book::find(string name)
{
    for (int i = 0; i < size; i++)
    {
        if (addresses[i].get_name() == name)
        {
            return i;
        }
    }
    return -1;
}



//end of Address_Book class



void find(string name, Address_Book addbook)
{
    int index = addbook.find(name);
    cout << index << endl;

    if (index > -1)
    {
        cout << addbook.location(index).get_name() << " is in room " << 
        addbook.location(index).get_room() << endl;
    }
    else
    {
        throw runtime_error("entry does not exist.");
    }
}


void remove_add(string name, Address_Book book)
{
    int exist = book.find(name);

    if (exist > -1)
    {
        book.remove_address(name);
    }
    else
    {
        throw runtime_error("entry does not existt.");
    }

}






int main()
{
    Address_Book addbook;
    string action, in_name, in_room;
    do
    {
        try
        {
            cout << "> ";
            cin >> action;

            if (action == "add")
            {
                cin >> in_name >> in_room;
                Address newadd(in_name, in_room);
                addbook.add(newadd);
            }
            else if (action == "move")
            {
                cin >> in_name >> in_room;
                addbook.move(in_name, in_room);
            }
            else if (action == "remove")
            {
                cin >> in_name;
                remove_add(in_name, addbook);
            }
            else if (action == "find")
            {
                cin >> in_name;
               find(in_name, addbook);
            }
            else if (action == "list")
            {
                addbook.sort();

                for (int i = 0; i < addbook.get_size(); i++)
                {
                cout << addbook.location(i).get_name() << " is in room 
                " << addbook.location(i).get_room() << endl;
                }
            }
            else if (action == "clear")
            {
                addbook.clear();
            }
            else
            {
                throw runtime_error("input mismatch.");
            }
        }
        catch (runtime_error& e)
        {
            cerr << "error: " << e.what() << endl;
        }
    }while (action != "exit");

    return 0;
}

导致问题的确切命令未在您的问题中指定,因此我四处寻找,直到代码因分段错误而崩溃。

Valgrind and Dr. Memory 是查找此类问题根本原因的绝佳工具。你的情况:

$ g++ -g 46865300.cpp
$ valgrind ./a.out
> add foo bar
> list
==102== Invalid read of size 8
==102==    at 0x4EF4EF8: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::string const&) (in /usr/lib64/libstdc++.so.6.0.19)
==102==    by 0x401354: Address::get_room() (46865300.cpp:33)
==102==    by 0x401C05: Address_Book::sort() (46865300.cpp:152)
==102==    by 0x4026A3: main (46865300.cpp:262)
==102==  Address 0x5a17410 is 8 bytes after a block of size 24 alloc'd
==102==    at 0x4C2A8A8: operator new[](unsigned long) (vg_replace_malloc.c:423)
==102==    by 0x4014BF: Address_Book::add(Address) (46865300.cpp:74)
==102==    by 0x40245C: main (46865300.cpp:243)

说下面的代码执行了越界访问:

150     for (int i = 0; i < size; i++)
151     {
152         if (addresses[i].get_room() == addresses[i + 1].get_room())
153         {
154             if (addresses[i].get_name() > addresses[i + 1].get_name())

我猜循环条件应该使用"size - 1"而不是"size"。

函数remove_add需要通过引用或指针获取通讯录对象。 现在的样子,它从地址簿的副本中删除。

它应该是这样的:

void remove_add(string name, Address_Book& book)
{
    int exist = book.find(name);

    if (exist > -1)
    {
        book.remove_address(name);
    }
    else
    {
        throw runtime_error("entry does not existt.");
    }

}

此外,您可能应该在以下函数中做一些不同的事情以防 size == 1。例如将 addresses 设置为 NULL、零或 nullptr(如果您的编译器支持)。

void Address_Book::remove_address(string name)
{
    Address* temp = new Address[size - 1];

    for (int i = 0; i < size; i++)
    {
        if (addresses[i].get_name() != name)
        {
            temp[i] = addresses[i];
        }
        else if (addresses[i].get_name() == name)
        {
            for (int j = i + 1; j < size; j++)
            {
                temp[i] = addresses[j];
                i++;
            }
            break;
        }
    }
    delete[] addresses;
    addresses = temp;
    size--;
}

祝你语言学习愉快:)