将键移出 std::map<> &&
Moving keys out of std::map<> &&
我想说 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;
}
但它不起作用,因为 it
(.first
) 中的键是 const
。任何提示如何解决它?注意:在我们的环境中,我不允许使用 C++17 函数 std::map::extract()
.
使用 const_cast
是否可以,因为 map
无论如何都会被破坏?
res.push_back(std::move(const_cast<std::unique_ptr<MyObj> &>(it.first)));
我想避免克隆 MyObj
。
我知道为什么不能修改std::map
容器的键,但是对于修改键后将立即销毁的地图仍然不允许修改吗?
是的,它仍然是不允许的。非常量访问密钥 可能 安全,如果你只是想在之后销毁地图,但标准和 std::map
接口不保证它是安全的不对适用于右值引用的规则提供任何放宽。
自 C++17 以来 std::map
所具有的是 extract()
,它将键值对完全从映射中删除和 returns 它作为 "node handle"。此节点句柄提供对密钥的非常量访问。因此,如果您要 move
节点句柄之外的指针,最终的销毁将发生在一个空指针上。
示例:
#include <utility>
#include <memory>
#include <vector>
#include <map>
template <typename K, typename V>
std::vector<K> extractKeys(std::map<K, V> && map)
{
std::vector<K> res;
while(!map.empty())
{
auto handle = map.extract(map.begin());
res.emplace_back(std::move(handle.key()));
}
return std::move(res);
}
int main()
{
std::map<std::unique_ptr<int>, int> map;
map.emplace(std::make_pair(std::make_unique<int>(3), 4));
auto vec = extractKeys(std::move(map));
return *vec[0];
}
Note: In our environment I'm not allowed to use C++17 function std::map::extract()
.
惭愧-它是为了解决这个问题而引入的。
Is it somehow ok to use const_cast
because map will be destructed anyway?
没有
I want to avoid cloning MyObj
.
对不起;您至少需要克隆密钥。
I know why keys of a std::map
container cannot be modified but is it still disallowed for a map that is going to be destructed immediately after the key modification?
是的。
地图的内部机制无法知道它的命运在等待。
答案说服我应该避免 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;
}
我想说 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;
}
但它不起作用,因为 it
(.first
) 中的键是 const
。任何提示如何解决它?注意:在我们的环境中,我不允许使用 C++17 函数 std::map::extract()
.
使用 const_cast
是否可以,因为 map
无论如何都会被破坏?
res.push_back(std::move(const_cast<std::unique_ptr<MyObj> &>(it.first)));
我想避免克隆 MyObj
。
我知道为什么不能修改std::map
容器的键,但是对于修改键后将立即销毁的地图仍然不允许修改吗?
是的,它仍然是不允许的。非常量访问密钥 可能 安全,如果你只是想在之后销毁地图,但标准和 std::map
接口不保证它是安全的不对适用于右值引用的规则提供任何放宽。
自 C++17 以来 std::map
所具有的是 extract()
,它将键值对完全从映射中删除和 returns 它作为 "node handle"。此节点句柄提供对密钥的非常量访问。因此,如果您要 move
节点句柄之外的指针,最终的销毁将发生在一个空指针上。
示例:
#include <utility>
#include <memory>
#include <vector>
#include <map>
template <typename K, typename V>
std::vector<K> extractKeys(std::map<K, V> && map)
{
std::vector<K> res;
while(!map.empty())
{
auto handle = map.extract(map.begin());
res.emplace_back(std::move(handle.key()));
}
return std::move(res);
}
int main()
{
std::map<std::unique_ptr<int>, int> map;
map.emplace(std::make_pair(std::make_unique<int>(3), 4));
auto vec = extractKeys(std::move(map));
return *vec[0];
}
Note: In our environment I'm not allowed to use C++17 function
std::map::extract()
.
惭愧-它是为了解决这个问题而引入的。
Is it somehow ok to use
const_cast
because map will be destructed anyway?
没有
I want to avoid cloning
MyObj
.
对不起;您至少需要克隆密钥。
I know why keys of a
std::map
container cannot be modified but is it still disallowed for a map that is going to be destructed immediately after the key modification?
是的。
地图的内部机制无法知道它的命运在等待。
答案说服我应该避免 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;
}