将键移出std :: map <> &&

时间:2019-10-07 11:18:45

标签: c++ stdmap

我想让import numpy as np import pandas as pd from scipy.stats.stats import pearsonr A=np.arange(16).reshape(4,4) B=np.arange(1038240).reshape(721,1440) A1=np.asarray(A) B1=np.asarray(B) X=pd.DataFrame(A1) Z1=pd.DataFrame(B1) R=X.apply(lambda s: Z1.corrwith(s)) R 0 1 2 3 0 1.0 1.0 1.0 1.0 1 1.0 1.0 1.0 1.0 2 1.0 1.0 1.0 1.0 3 1.0 1.0 1.0 1.0 4 1.0 1.0 1.0 1.0 ... ... ... ... ... 1435 1.0 1.0 1.0 1.0 1436 1.0 1.0 1.0 1.0 1437 1.0 1.0 1.0 1.0 1438 1.0 1.0 1.0 1.0 1439 1.0 1.0 1.0 1.0 [1440 rows x 4 columns] 函数从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。有什么技巧怎么解决呢?注意:在我们的环境中,不允许使用C ++ 17函数const

使用std::map::extract()是否可以正常使用,因为const_cast仍然会被破坏?

map

我要避免克隆res.push_back(std::move(const_cast<std::unique_ptr<MyObj> &>(it.first)));

我知道为什么MyObj容器的键不能被修改,但是对于在键修改后将立即被销毁的地图仍然不允许吗?

3 个答案:

答案 0 :(得分:3)

是的,仍然不允许这样做。如果您以后要销毁地图,则非常量访问键可能是安全的,但是按标准不能保证安全,并且std::map接口不能保证安全提供适用于右值引用的任何形式的规则放松。

自C ++ 17以来std::map 所具有的是extract(),它将键-值对完全从映射中提取出来,并以“节点句柄”。该节点句柄提供对密钥的非常量访问。因此,如果要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];
}

答案 1 :(得分:3)

  

注意:在我们的环境中,不允许使用C ++ 17函数std::map::extract()

羞耻-它是为了解决这个问题而引入的。

  

使用const_cast是否可以正常使用,因为地图仍然会被破坏?

否。

  

我要避免克隆MyObj

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

  

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

是的

地图的内部机制无法得知其命运正在等待。

答案 2 :(得分:0)

答案说服我,我应该避免const_cast-ing。经过一些分析,我意识到代码中代码的使用是非常孤立的,因此我可以做一个小的重构来避免const问题。

这是结果:

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