如何正确使用带有智能指针和自定义类作为键和值的映射

时间:2019-05-07 18:13:25

标签: c++ dictionary polymorphism smart-pointers

我正在尝试制作一个地图,在该地图中,我将以“团队”作为键,而“员工”的矢量则是多态的。将来某些数据将从文件中加载,用户将可以随时添加新团队和员工。

这是我想出的地图:

std::map<std::unique_ptr<Team>, std::unique_ptr<std::vector<std::unique_ptr<Employee>>>> teams;

这是一些测试代码,我试图在其中添加新的团队和成员:

bool Company::addTeam(const std::string & projectName)
{
    teams.emplace(std::unique_ptr<Team>(new Team(projectName)), std::unique_ptr<std::vector<std::unique_ptr<Employee>>>(new std::vector<std::unique_ptr<Employee>>()));
    for (std::map<std::unique_ptr<Team>, std::unique_ptr<std::vector<std::unique_ptr<Employee>>>>::iterator it = teams.begin(); it != teams.end(); ++it) {
        std::cout << it->first.get()->getProjectName();
        it->second.get()->emplace_back(std::unique_ptr<Employee>(new Programmer("David", "Beckham", "9803268780", "Djoe Beckham", Employee::LevelThree, projectName)));
        std::cout << "\n" << it->second.get()->at(0)->toString();
    }


    return false;
}

该代码运行良好,无法打印员工数据,但在关闭应用程序后,它将引发异常,Visual Studio打开delete_scalar.cpp并在此代码处触发断点:

void __CRTDECL operator delete(void* const block) noexcept
{
    #ifdef _DEBUG
    _free_dbg(block, _UNKNOWN_BLOCK); // break point
    #else
    free(block);
    #endif
}

我正试图找出我做错了什么以及如何解决。如果与该问题有关,则我所有雇员类的析构函数都为空。如果我的想法看起来很愚蠢,并且有更简单的方法可以实现我的目标,请告诉我。预先感谢。

2 个答案:

答案 0 :(得分:1)

在设计方面,一个人可以同时在不同的团队中扮演多个角色。可以是将人与团队联系起来的另一类Role。这两个团队都没有,但是从概念上讲,没有角色拥有人对象,因此Role可以使用普通指针将PersonTeam链接起来。

答案 1 :(得分:1)

您的idea could work(如果您在一个班级中没有问题)。由于缺少零件,很难分辨。

但是,这不是可行的方法!

映射旨在按值使用索引。一个典型的用例是用一个已经存在的密钥找回一个项目。当然,您可以将指针用作键,但是指针将充当一种id,而无需进行任何多态操作。

另一方面,unique_ptr旨在确保唯一的所有权。因此,每个指针值仅存在一个唯一副本。这使得很难用作地图值:

auto team2 = make_unique<Team>(); 
teams [team2] = make_unique<vector<unique_ptr<Employee>>>();  // doesn't compile

上面的代码无法编译,因为team2unique_ptr,因此无法复制到索引参数中。使用它来搜索或插入项目时,需要移动它:

teams [std::move(team2)] = make_unique<vector<unique_ptr<Employee>>>(); //compiles
assert (team2); // ouch

但是一旦移动,unique_ptr中的team2值将不再为空,因为唯一指针在map键中并且是唯一的,因此shared_ptr现在为空。 这意味着您将永远不会找到增加的团队

更好的选择?

如果您想真正使用多态指针作为映射键,则至少应使用unique_ptr,以便代码中可以存在多个副本。但我建议您仅将值用作键

现在到地图的值部分。从vectorsizeof(vector<...>)没有好处:向量本身不是多态的,向量被很好地设计用于复制,移动等。此外,vector<unique_ptr<Employee>>即使对于非常大的向量也很小。

如果要让地图中的矢量拥有 Employees,请使用vector<shared_ptr<Employee>>;如果要共享矢量的内容,请使用{{1}} 。