2011-12-29 44 views
1

okkk,以及我不得不重写我的所有代码和我的帖子,所以我希望我能得到帮助。我有两个类:PersonManager和Person。 PersonManager的目的是跟踪所有人员和人员的姓名。这里是我的全码:返回NULL将尝试使用的对象? (获取核心转储 - C++新手)

的main.cpp

#include <string> 
#include <sstream> 
#include <iostream> 
#include <map> 

using namespace std; 

class Person 
{ 
public: 
    Person(); 
    void SetName(string s) {Name_ = s;} 
    string GetName() const {return Name_;} 
private: 
    string Name_; 
}; 

Person::Person() 
{ 
    Name_ = ""; 
} 

class PersonManager 
{ 
public: 
    PersonManager(); 
    void NewPerson(string); 
    void GetRidOfPerson(string); 
    Person *GetPerson(string); 
    void Close(); 
private: 
    map<string, Person *> PersonMap_; 
}; 

PersonManager::PersonManager() 
{ 
    PersonMap_.clear(); 
} 

void PersonManager::NewPerson(string name) 
{ 
    for (map<string, Person *>::iterator it = PersonMap_.begin(); 
     it != PersonMap_.end(); 
     it++) 
    { 
     if (it->first.compare(name) == 0) 
    { 
     return; // person already exists 
    } 
    } 

    Person *person = new Person; 
    PersonMap_.insert(pair<string, Person *>(name, person)); 
    cout << "Created person: " << name << ".\n"; 
} 

Person *PersonManager::GetPerson(string name) 
{ 
    for (map<string, Person *>::iterator it = PersonMap_.begin(); 
     it != PersonMap_.end(); 
     it++) 
    { 
     if (it->first.compare(name) == 0) 
    { 
     return it->second; 
    } 
    } 

    cout << "Person: " << name << " not found." << endl; 
    return NULL; 
} 

void PersonManager::GetRidOfPerson(string name) 
{ 
    for (map<string, Person *>::iterator it = PersonMap_.begin(); 
     it != PersonMap_.end(); 
     it++) 
    { 
     if (it->first.compare(name) == 0) 
    { 
     delete it->second; 
     PersonMap_.erase(it); 
     cout << "Deleted person: " << name << ".\n"; 
     return; 
    } 
    } 

    cout << "Couldn't find person " << name << " for deletion.\n"; 
} 

void PersonManager::Close() 
{ 
    for (map<string, Person *>::iterator it = PersonMap_.begin(); 
     it != PersonMap_.end(); 
     it++) 
    { 
     delete it->second; 
     PersonMap_.erase(it); 
     cout << "Deleted person: " << it->first << ".\n"; 
    } 

    PersonMap_.clear(); 
} 

int main(void) 
{ 
    PersonManager person_manager; 
    person_manager.NewPerson("Tom"); 
    person_manager.NewPerson("Tom"); 
    person_manager.GetRidOfPerson("Tom"); 
    person_manager.GetRidOfPerson("Abel"); 
    person_manager.GetPerson("Tom")->SetName("Bob"); 
    cout << person_manager.GetPerson("Tom")->GetName() << endl; 
    cout << person_manager.GetPerson("Bob")->GetName() << endl; 
    person_manager.Close(); 
    return 0; 
} 

所有在检查的人不在列表中的main()函数的代码是用于测试目的!

如果你

person_manager.NewPerson("Tom"); 

,然后你做

person_manager.GetPerson("Tom")->SetName("Billy"); 

,然后尝试做:

person_manager.GetPerson("Tom")->GetName(); 

它将返回NULL,然后段错误。

所以在这个片断:

Person *PersonManager::GetPerson(string name) 
{ 
    for (map<string, Person *>::iterator it = PersonMap_.begin(); 
     it != PersonMap_.end(); 
     it++) 
    { 
     if (it->first.compare(name) == 0) 
    { 
     return it->second; 
    } 
    } 

    cout << "Person: " << name << " not found." << endl; 
    return NULL; 
} 

,所以我想出了一个解决方案:

Person *person = new Person; 
return person; 

问题是^是,是,我有未分配的内存。有没有其他方法可以做到这一点?

所有帮助表示赞赏,谢谢!

+0

您可能需要重命名PersonManager :: PersonGinger()。 – 2011-12-29 05:53:24

+0

你是什么意思 – evolon696 2011-12-29 05:55:04

+1

有一个潜在的令人反感的方法名称。 – 2011-12-29 05:58:34

回答

1

我看到几个问题。首先,至少从我所了解的 代码中,PersonManager::PersonMap_使用的密钥是完全独立的 中的任何数据,实际为Person。所以序列:

person_manager.NewPerson("Tom"); 
person_manager.GetPerson("Tom")->SetName("Billy") 
std::cout << person_manager.GetPerson("Tom")->GetName() << std::endl; 

是完全有效的,并输出“比利”。这可能不是你想要的, 但这就是你写的。在main

您的测试代码失败,当然,因为你已经做 person_manager.GetRidOfPerson("Tom")后访问 结果person_manager.GetPerson("Tom")

更一般地说,从外观上看,我猜想你正在试图用 键掉人的名字。在这种情况下,我会使名称 字段Person不可变,并要求在 构造函数中初始化它。已经这样做了,我既可以使用std::set(基于名称的 比较功能),或者如果所有PersonPersonManager创建 ,我可以保证不变,在 std::map关键是始终equalt在名称字段相应的 Person。其次,任何时候您访问任何类型的关联数据时,都必须为元素不存在的情况准备好 。有 处理这个方法很多:

  • Automaticall插入,一些默认值。 (这是std::map的 的行为,如果你使用[]访问的元素。)

  • 返回一些默认值,而无需插入。

  • 返回某种小写—返回指针,空指针作为sentinal,是一个广泛的约定。

  • 引发异常。如果找不到该值,则有效的选择可以是 认为是例外。

  • 中止程序。一个有效的选择,如果值的存在可以是 考虑precondion(通常不是这种情况)。

如果关键是从外部数据源中读取一个字符串,最后两个 病例很可能是不适用的(虽然有点依赖于异常的 数据源)。也不是第一个,真的;与一个 损坏的数据源(或顽固的用户,如果数据源是 交互式输入),你很快就会得到一个包含大多数 默认值的地图。大多数情况下,第二个或第三个解决方案强制使用 ,仅在缺省值容易识别为 时才有效。客户代码必须检查在继续之前查找成功 (就像客户代码在进行之前必须检查输入成功 一样)。

所以你的情况,要么你返回一个空指针(其中客户端代码 必须检查之前继续—这对大多数 函数返回一个指针的规则);或者返回一个引用,在 失败的情况下返回 引用静态变量或PersonManager的成员;如果你可以定义一个独特的无效的 Person的实例,这第二个是唯一有效的。或者,根据您的最终申请中关键值 的位置,如果该值不存在,则可以考虑抛出 异常。但是你必须做一些事情,并且客户端代码必须能够处理密钥值不是 的情况。这是没有办法的。

+0

我不需要这个了,但很多信息谢谢我以后使用 – evolon696 2012-01-12 18:43:31

2

而不是返回具有指向Person指针的地图,有实际的类的实例,然后返回一个引用。如果找不到Person,则返回一个静态成员变量,类似于map<>::end()所做的。

事情是这样的:

class PersonManager 
{ 
public: 
    // ... 
    Person &GetPerson(string); 

    static Person NoSuchPerson; 

private: 
    map<string, Person> PersonMap_; 
}; 

Person PersonManager::NoSuchPerson; 

Person &PersonManager::GetPerson(string name) 
{ 
    for (map<string, Person>::iterator it = PersonMap_.begin(); 
     it != PersonMap_.end(); 
     it++) 
    { 
     if (it->first.compare(name) == 0) 
     { 
      return it->second; 
     } 
    } 

    cout << "Person: " << name << " not found." << endl; 
    return NoSuchPerson; 
} 
+0

好主意。我会利用这个,谢谢。 – evolon696 2011-12-29 06:01:39

2

检查是否从GetPerson返回的值是NULL你使用它之前。一些沿线的:

Person *person = person_manager.GetPerson("Tom"); 
if (person == NULL) { 
    std::cout << "Tom not found!" << std::endl; 
} else { 
    // Do stuff with person 
} 
相关问题