【问题标题】:how to transfer a unique_ptr from a priority queue to a queue如何将 unique_ptr 从优先级队列传输到队列
【发布时间】:2018-06-24 14:25:07
【问题描述】:

在“短”中,我有一个 priority_queue 选择 k unordered_set<int> 满足特定条件。我想将它们(哈希集)作为queue 返回。

由于priority_queue 的创建和维护需要元素交换,因此我使用指针而不是unordered_set<int> 作为priority_queue 的条目。

因此返回类型应该是queue< smart_ptr<unordered_set<int>> >

如果我使用shared_ptr,代码可以正常工作,但我希望使用unique_ptr,因为它更经济,并且客户承诺将其用作unique_ptr

如何使用unique_ptr实现以下代码?

------------------详细说明-------------------------- -----

我有一个函数可以从文件中读取保留k 的行,这些行的大小最接近参考大小。说,如果k=2,参考大小是5,文件包含6行大小(这一行中的整数)3,5,6,20,2,1k-closest 行分别是大小为56 的两条线。

我使用大小为kpriority_queue 和自定义比较器来实现目标。我决定返回一个包含所选k-closest 行的queue,因为客户端不想知道比较器是如何实现的(比较器是priority_queue 模板的参数)。

using ptr_type = shared_ptr<unordered_set<int>>;
// ???????????????????????????????????????
// using ptr_type = unique_ptr<unordered_set<int>>; // unique_ptr does not work
// ???????????????????????????????????????
// Is it possible to transfer unique_ptr entries from a priority_queue to a queue?
using pair_comm_type = pair<int,ptr_type>;

queue<pair_comm_type> f() {
    // myFile.txt is a space separated file of integers.
    // Different lines may have different lengths (number of integers)
  string inputFile = "myFile.txt";
  const int TOP_K_LINE = 3;

    // to open a file
  ifstream fin(inputFile.c_str());
  string readBuffer;
  // The file opened

    // to define a priority_queue
    // define customized compare function, such that retained lines have size
    // closest to the reference value.
  double referenceSize = log10(10.0);
  auto comp = [&referenceSize](const pair_comm_type &LHS, const pair_comm_type &RHS)
      { return abs(log10(LHS.first)-referenceSize) 
      < abs(log10(RHS.first)-referenceSize); };
  priority_queue<pair_comm_type, vector<pair_comm_type>, decltype(comp)> myHeap(comp);
  // the priority_queue defined

  int bufIntValue = -1;
  int curMinArraySize = -1; // auxilliary variable, to reduce heap top access
    // to read the file line by line
  while (getline(fin,readBuffer)) {
      // to read int in each line to a hash set
    istringstream S(readBuffer);
    ptr_type lineBufferPtr(new unordered_set<int>);
    while (S>>bufIntValue) lineBufferPtr->insert(bufIntValue);
// one line read

      // to decide retain or not based on the length of this line
    int arraySize = lineBufferPtr->size();
    if (myHeap.size() < TOP_K_LINE) {
      // We can add new lines as long as top-k is not reached
      myHeap.emplace(arraySize,std::move(lineBufferPtr));
      curMinArraySize = myHeap.top().first;
      continue;
    }
    if (arraySize <= curMinArraySize) continue;
    myHeap.emplace(arraySize,std::move(lineBufferPtr));
    myHeap.pop();
    curMinArraySize = myHeap.top().first;
  }
  // all lines read
  fin.close();

    // to transfer values from the priority_queue to a queue
    // ???????????????????????????????????????
    // Is it possible that we can make changes here such that unique_ptr can also work??????
    // ???????????????????????????????????????
  queue<pair_comm_type> Q;
  while (!myHeap.empty()) {
    auto temp = myHeap.top();
    myHeap.pop();
    Q.emplace(temp.first,std::move(temp.second));
  }

  /*
  while (!Q.empty()) {
    printf("%d, ",Q.front().first);
    Q.pop();
  }
  printf("\n");
  */
  return Q;
}

【问题讨论】:

  • “由于priority_queue的创建和维护需要元素交换,我使用指针而不是unordered_set作为priority_queue的入口。” - 真的吗?必要的? unordered_set&lt;int&gt; 可以交换/移动。
  • 听起来您需要在priority_queue 中的元素上调用 .release() 才能将其删除(因此PQ 不会删除指针)。你可能能够做到:unique_ptr tmp = std::move(pq.front()); pq.pop();返回 tmp;但我还没有查看 unique_ptr 是否可移动。

标签: c++ c++11 stl smart-pointers


【解决方案1】:

STL 容器被设计为移动,当您这样做时,它与使用 指针 一样有效。事实上,它们在内部使用 指针,因此您不必这样做。

我会考虑只使用这样的值:

using pair_comm_type = pair<int, unordered_set<int>>;

queue<pair_comm_type> f() {

  string inputFile = "myFile.txt";
  const int TOP_K_LINE = 3;

  ifstream fin(inputFile.c_str());
  string readBuffer;

  double referenceSize = log10(10.0);
  auto comp = [&referenceSize](const pair_comm_type &LHS, const pair_comm_type &RHS)
      { return abs(log10(LHS.first)-referenceSize)
      < abs(log10(RHS.first)-referenceSize); };
  priority_queue<pair_comm_type, vector<pair_comm_type>, decltype(comp)> myHeap(comp);

  int bufIntValue = -1;
  int curMinArraySize = -1;

  while (getline(fin,readBuffer)) {
    istringstream S(readBuffer);

    // no need to use pointers here
    unordered_set<int> lineBufferPtr;
    while (S>>bufIntValue)
        lineBufferPtr.insert(bufIntValue);

    int arraySize = lineBufferPtr.size();
    if (myHeap.size() < TOP_K_LINE) {

      myHeap.emplace(arraySize,std::move(lineBufferPtr));
      curMinArraySize = myHeap.top().first;
      continue;
    }
    if (arraySize <= curMinArraySize) continue;
    myHeap.emplace(arraySize,std::move(lineBufferPtr));
    myHeap.pop();
    curMinArraySize = myHeap.top().first;
  }

  fin.close();

  // Use std::move to transfer the top() element which will be
  // just as efficient as using pointers

  queue<pair_comm_type> Q;

  while (!myHeap.empty()) {
    auto temp = std::move(myHeap.top()); // USE MOVES
    myHeap.pop();
    Q.push(std::move(temp));
  }

  return Q;
}

【讨论】:

    【解决方案2】:

    @Galik 的解决方案有效。

    至于最初的问题,简单的答案是否定的。我们无法将 unique_ptr 转移出 priority_queue。

    unique_ptrcopy constructor 的参数是 const 引用被删除。 priority_queue::top() 的返回类型是 const reference。因此我们不能使用返回值来创建一个新的unique_ptr 对象。

    【讨论】:

      猜你喜欢
      • 2013-05-15
      • 1970-01-01
      • 1970-01-01
      • 2011-03-20
      • 1970-01-01
      • 2011-12-20
      • 1970-01-01
      • 2021-01-07
      • 2014-01-19
      相关资源
      最近更新 更多