简体   繁体   English

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

[英]How to correctly use map with smart pointers and custom classes as key and value

I'm trying to make map in which i will hold Teams as key and vector of Employees which are polymorphic as value. 我正在尝试制作一个地图,在该地图中,我将团队作为关键,将员工作为矢量,而价值则是多态的。 Some of the data will be loaded from file in future and the user will be able to add new teams and employees at any time. 将来,某些数据将从文件中加载,用户将可以随时添加新的团队和员工。

This is the map that i came up with: 这是我想出的地图:

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

And this is some test code where i tried to add new team and a member to it: 这是一些测试代码,我尝试在其中添加新的团队和成员:

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

The code runs fine and im able to print the employee data but after closing the application it throws exception and visual studio open delete_scalar.cpp and triggers a breakpoint at this code : 该代码运行良好,无法打印员工数据,但在关闭应用程序后,它将引发异常,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
}

I'm trying to find out what i'm doing wrong and how to fix it. 我正在尝试找出我在做什么以及如何解决。 I have empty destructors for all Employees classes if that have something to do with the problem. 如果与该问题有关,则我所有雇员类的析构函数都为空。 If my idea looks very stupid and there is easier way to accomplish my goal please tell me. 如果我的想法看起来很愚蠢,并且有更简单的方法可以实现我的目标,请告诉我。 Thanks in advance. 提前致谢。

Design-wise, one person can have multiple roles in different teams at the same time. 在设计方面,一个人可以同时在不同的团队中扮演多个角色。 It can be another class Role linking a person to a team. 可以是将人员链接到团队的另一类Role Neither team, no role conceptually own person objects though, so Role could use plain pointers to link Person with Team . 这两个团队都不是,但是角色在概念上都没有人对象,因此Role可以使用简单的指针将PersonTeam链接。

Your idea could work , if you would not have a problem within one of your class. 如果您在同一个班级中没有问题,您的想法可能会奏效 Due to the missing parts, it's difficult to tell. 由于缺少零件,很难分辨。

However, this is not the way to go !! 但是,这不是要走的路!

A map is meant to work with an index by value. 映射旨在按值使用索引。 A typical use case is to find back an item with an already existing key. 一个典型的用例是用一个已经存在的密钥找回一个项目。 Of course, you could use pointers as key, but the pointer would then act as a kind of id without any polymorphic operations. 当然,您可以将指针用作键,但是指针将充当一种id,而无需进行任何多态操作。

On the other side, a unique_ptr is designed to ensure unique ownership. 另一方面,设计了unique_ptr以确保唯一的所有权。 So only one unique copy of each pointer value exist. 因此,每个指针值仅存在一个唯一副本。 This makes it very difficult to use as map value: 这使得很难用作地图值:

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

The above code doesn't compile, because team2 is a unique_ptr and cannot be copied into the indexing parameter. 上面的代码无法编译,因为team2unique_ptr ,因此无法复制到索引参数中。 Using it for searching or inserting an item, would require to move it: 使用它来搜索或插入项目时,需要移动它:

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

But once moved, the unique_ptr value is no longer in team2 which is now empty since the unique pointer is in the map key and it's unique. 但是,一旦移动时, unique_ptr值不再team2现在是空的,因为独特的指针是在地图的关键,它是独一无二的。 This means that you will never ever find back an added team . 这意味着您将永远不会找到增加的团队

Better alternatives ? 更好的选择?

If you would want to really use a polymorphic pointer as a map key, you should at least use a shared_ptr , so that several copies can exist in your code. 如果要真正使用多态指针作为映射键,则至少应使用shared_ptr ,以便代码中可以存在多个副本。 But I'd suggest that you use values only as a key 但我建议您仅将值用作键

Now to the value part of the map. 现在到地图的价值部分。 There is no benefit of making a unique_ptr of a vector : the vector itself is not polymorphic, and vectors are well designed for copying, moving and so on. 创建vectorunique_ptr没有任何好处:向量本身不是多态的,向量的设计很好,可以进行复制,移动等操作。 Furthermore sizeof(vector<...>) is small even for very large vectors. 此外,即使对于非常大的向量, sizeof(vector<...>)也很小。

Use a vector<unique_ptr<Employee>> if you want the vector in the map to own the Employees , or vector<shared_ptr<Employee>> if you intend to share the content of the vector. 如果要让地图中的矢量拥有 Employees ,请使用vector<unique_ptr<Employee>>如果要共享矢量的内容,请使用vector vector<shared_ptr<Employee>>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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