簡體   English   中英

將鍵移出 std::map<> &&

[英]Moving keys out of std::map<> &&

我想說getKeys() function 從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 function std::map::extract()

使用const_cast是否可以,因為map無論如何都會被破壞?

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

我想避免克隆MyObj

我知道為什么std::map容器的鍵不能被修改,但是對於在鍵修改后將立即被破壞的 map 是否仍然不允許?

是的,它仍然是不允許的。 如果您之后要銷毀 map,對密鑰的非常量訪問可能是安全的,但標准不能保證它是安全的,並且std::map接口不提供任何形式的規則放寬這適用於右值引用。

但是,自 C++17 以來, std::map確實擁有的是extract() ,它從 map 中提取了一個鍵值對,並將其作為“節點句柄”完全返回。 此節點句柄提供對密鑰的非常量訪問。 因此,如果您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];
}

注意:在我們的環境中,我不允許使用 C++17 function std::map::extract()

恥辱 - 它被引入來解決這個問題。

使用const_cast是否可以,因為 map 無論如何都會被破壞?

不。

我想避免克隆MyObj

對不起; 您至少需要克隆密鑰。

我知道為什么std::map容器的鍵不能被修改,但是對於在鍵修改后將立即被破壞的 map 是否仍然不允許?

是的。

地圖的內部機制無法知道它的命運正在等待。

答案說服了我,我應該避免使用 const_cast-ing。 經過一些分析,我意識到我的 map 的使用在代碼中是非常孤立的,所以我可以做一個小的重構來避免 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;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM