【问题标题】:why this reference set not allowed?为什么这个参考集不允许?
【发布时间】:2018-09-02 17:55:50
【问题描述】:

C++ 新手,我想如果我定义一个容器并在里面指定它的类型为string,那么它应该从string 中直接出来,我想有一个引用变量别名到这个字符串。显然,我在这里遗漏了一些东西,因为编译器抱怨它无法将 void 转换为字符串。有人可以帮忙澄清一下吗?谢谢。

#include <queue>
#include <string>
#include <iostream>

using namespace std;


int main(int argc, char** argv) {
    std::queue<std::string> myqueue;

    myqueue.push("val1");
    myqueue.push("val2");

    while (!myqueue.empty()) {
        std::string & s = myqueue.pop();
        std::cout << s << endl;
    }
}

【问题讨论】:

标签: c++


【解决方案1】:

那是因为std::queue::pop 没有返回任何东西(无效)。

如果你想访问第一个元素然后删除它,你应该使用std::queue::front 然后std::queue::pop

while (!myqueue.empty()) {
  std::string & s = myqueue.front();
  std::cout << s << endl;
  myqueue.pop();
}

我在std::cout &lt;&lt; s &lt;&lt; endl; 之后移动了myqueue.pop(); 以避免悬空引用(对不再存在的对象的引用)。

【讨论】:

  • @arorias *whispers* queue::front,而不是 queue::back *whispers*
  • 我的错,现在应该没问题了:)
【解决方案2】:

queue::pop 的返回类型为void 并且仅删除第一个元素。如果你想保留它的值,那么首先用front() 检索它,你应该按值而不是按引用来保留它,因为它被弹出的那一刻,对它的引用就变得悬空了。

std::string next{myqueue.front()};
myqueue.pop();

【讨论】:

    【解决方案3】:

    std::queue::pop() 不返回任何内容。它只是删除队列的第一个元素。您必须使用std::queue::front() 来获取对第一个元素的引用(并将其存储在s)然后调用std::queue::pop() 从队列中删除第一个元素之后你使用@987654328 @ 并且你不再需要它了。

    在调用std::queue::pop() 之后不要使用存储在s 中的引用很重要,因为在幕后std::queue 包装了一个std::dequeue 对象,std::queue::pop() 在其上调用std::dequeue::pop_first()std::dequeue::pop_first() 的文档页面指出:

    迭代器和对被擦除元素的引用无效。

    您的代码可能是:

    while (!myqueue.empty()) {
        // get a reference to the first element of the queue
        std::string & s = myqueue.front();
        // use it to handle the element
        std::cout << s << endl;
        // remove the first element of the queue; this invalidates all references to it
        myqueue.pop();
        // the reference stored in `s` is invalid now; don't use it any more
    }
    

    【讨论】:

      【解决方案4】:

      从队列中移动元素并立即调用pop()

      当您使用队列的元素时,而不是:

      • 存储对您即将从队列中pop() 的元素的引用,或者
      • front() 复制元素以避免悬空引用场景,

      您可以将front() 元素移动出队列,并立即在队列中调用pop()。例如

      #include <iostream>
      #include <queue>
      #include <string>
      #include <utility>
      
      template<typename T>
      T removeFrontFromOfQueue(std::queue<T>& q) {
          T front = std::move(q.front());
          q.pop();
          return front;  // Should be able to rely on NRVO, and if not, a move ctor.
      }
      
      int main() {
          std::queue<std::string> myqueue({"val1", "val2"});
      
          while (!myqueue.empty()) {
              std::string s = removeFrontFromOfQueue(myqueue);
              std::cout << s << " ";
          }  // val1 val2
      }
      

      如以下问答中所述:

      这是安全的。


      限制对front()对象的引用的生命周期

      或者,如果您选择存储对队列的front() 的引用,请考虑在对队列调用pop() 之前限制引用的生命周期。例如:

      while (!myqueue.empty()) {
          {
              const std::string& s = myqueue.front();
              std::cout << s << " ";
          }
          myqueue.pop();
      } // val1 val2 
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-09-07
        • 1970-01-01
        • 2013-07-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-02-19
        相关资源
        最近更新 更多