C++ 将关键帧移出std::map<&燃气轮机&&;

C++ 将关键帧移出std::map<&燃气轮机&&;,c++,stdmap,C++,Stdmap,我想让getKeys()函数从map中获取不可复制的键: class MyObj { // ... complex, abstract class... }; struct Comparator { bool operator()(std::unique_ptr<MyObj> const &a, std::unique_ptr<MyObj> const &b); }; std::vector<std::unique_ptr<MyObj&

我想让
getKeys()
函数从
map
中获取不可复制的键:

class MyObj {
  // ... complex, abstract class...
};

struct Comparator { bool operator()(std::unique_ptr<MyObj> const &a, std::unique_ptr<MyObj> const &b); };

std::vector<std::unique_ptr<MyObj>> getKeys(std::map<std::unique_ptr<MyObj>, int, Comparator> &&map) {
  std::vector<std::unique_ptr<MyObj>> res;
  for (auto &it : map) {
    res.push_back(std::move(it.first));
  }
  return res;
}
我想避免克隆
MyObj


我知道为什么不能修改
std::map
容器的键,但是对于在键修改后立即销毁的映射,仍然不允许修改吗?

是的,仍然不允许。如果您只是想在事后销毁映射,那么对密钥的非常量访问可能是安全的,但是标准并不能保证它是安全的,
std::map
接口也没有提供任何适用于右值引用的规则的放松

然而,自C++17以来,
std::map
所拥有的是
extract()
,它将一个键值对从映射中完全剥离出来,并将其作为“节点句柄”返回。此节点句柄提供对密钥的非常量访问。因此,如果要
将指针移出该节点句柄,则最终将对空指针进行销毁

例如:

#包括
#包括
#包括
#包括
模板
标准::向量提取键(标准::映射和映射)
{
std::向量res;
而(!map.empty())
{
自动句柄=map.extract(map.begin());
res.emplace_back(std::move(handle.key());
}
返回std::移动(res);
}
int main()
{
地图;
映射位置(std::make_pair(std::make_unique(3,4));
自动向量=提取键(标准::移动(映射));
返回*vec[0];
}
注意:在我们的环境中,我不允许使用C++17函数
std::map::extract()

羞耻感-它的出现是为了解决这个问题

使用
const\u cast
是否可以,因为地图无论如何都会被破坏

res.push_back(std::move(const_cast<std::unique_ptr<MyObj> &>(it.first)));
没有

我想避免克隆
MyObj

对不起;您至少需要克隆密钥

我知道为什么不能修改
std::map
容器的键,但是对于在键修改后立即销毁的映射,仍然不允许修改吗


地图的内部机制无法知道它的命运在等待着我。

答案让我相信我应该避免使用const_-cast-ing。经过一些分析,我意识到我的映射在代码中的使用是非常孤立的,因此我可以进行一个小的重构来避免常量问题

结果如下:

class MyObj {
  // ... complex, abstract class...
};

struct Comparator { bool operator()(MyObj const *a, MyObj const *b); };

// key is a pointer only, value holds the key object and the effective "value"
struct KeyAndVal { std::unique_ptr<MyObj> key; int val; };
using MyMap = std::map<MyObj *, KeyAndVal, Comparator>;

// Example how emplace should be done
auto myEmplace(MyMap &map, std::unique_ptr<MyObj> key, int val) {
  auto *keyRef = key.get();  // to avoid .get() and move in one expr below
  return map.emplace(keyRef, KeyAndVal{ std::move(key), val });
}

std::vector<std::unique_ptr<MyObj>> getKeys(MyMap map) {
  std::vector<std::unique_ptr<MyObj>> res;
  for (auto &it : map) {
    res.push_back(std::move(it.second.key));
  }
  // here 'map' is destroyed but key references are still valid
  // (moved into return value).
  return res;
}
类MyObj{
//…复杂的抽象类。。。
};
结构比较器{bool操作符()(MyObj常量*a,MyObj常量*b);};
//key仅为指针,value保存key对象和有效的“value”
结构KeyAndVal{std::uniqueptrkey;int val;};
使用MyMap=std::map;
//应如何安置的示例
自动myEmplace(MyMap&map,std::unique_ptr key,int val){
auto*keyRef=key.get();//避免.get()并在下面的一个表达式中移动
返回map.emplace(keyRef,KeyAndVal{std::move(key),val});
}
std::vector getkey(MyMap){
std::向量res;
用于(自动&it:map){
res.push_back(std::move(it.second.key));
}
//此处“地图”已销毁,但关键引用仍然有效
//(移动到返回值中)。
返回res;
}

你能从
std::unique_ptr
切换到
std::shared_ptr
吗?请看下面我如何解决这个问题的答案。删除一个又一个键可能会导致很多树重新平衡。不过,这似乎是唯一完全合法的再次取出钥匙的方法…@阿肯卡瓜同意。我想在这种情况下,我可能会结合使用
const\u cast
,并希望达到最好的效果:-你注意到OP不允许使用C++17吗?在我看来,他/她似乎知道
std::map::extract
,只是不能使用它。你答案的第二部分对我来说似乎完全多余,包括整个代码。(还要注意,您的
extractKeys
函数将只接受带有默认comparator和allocator模板参数的
map
s,这不是OP的情况。)不,我错过了OP消息的那一部分(但请记住,答案应该是广泛适用的,而不仅仅适用于原始提问者)。该代码旨在说明该技术,而不是未经修改就使用。它们应该适用于
const_cast
::的问题思路。