【问题标题】:How to insert a conditional_variable object into a Vector?如何将 conditional_variable 对象插入到 Vector 中?
【发布时间】:2015-02-03 17:28:34
【问题描述】:

conditional_variable 不是 CopyConstructible、MoveConstructible、CopyAssignable、MoveAssignable。

我们可以这样打电话吗

vector<conditional_variable> cond;

conditional_variable c1;
conditional_variable c2;
cond.push_back(c1);
cond.push_back(c2);

在这些情况下正确的方法是什么

【问题讨论】:

  • 你可以试试vector&lt;unique_ptr&lt;conditional_variable&gt;&gt;
  • 我想知道为什么需要 vectorcondition_variable 开始。解决什么问题?
  • 也许std::vector::emplace_back 能解决问题?
  • @Julian 不适用于向量,因为它可能会重新分配。
  • @T.C.是的,不幸的是你是对的...... :-(

标签: c++ c++11 vector


【解决方案1】:

您可以使用带大小参数的构造函数创建一个可以默认构造但不能复制或移动的向量:

std::vector<std::condition_variable> cv_vec(20);

这样的向量不能增长,但可以用pop_back()clear() 缩小(但不能用erase()resize())。

另外,由于所有事情都可以通过额外的间接级别来解决,因此您可以使用std::unique_ptr&lt;std::condition_variable&gt; 的向量。

现在,到底为什么有人要为像 condition_variable 这样的同步原语这样做,我不知道...

【讨论】:

  • 感谢 T.C 的回复。我不想像这样使用 conditional_variable 向量。问题基本上是找到一种在向量中使用没有复制构造函数的类的方法。因此,在这种情况下,我将采用 std::unique_ptr 方式。
【解决方案2】:

不,你不能, 我建议您使用vector&lt;unique_ptr&lt;conditional_variable&gt;&gt;。然后您可以分配一个新的conditional_variable 并将其添加到您的向量中

【讨论】:

    【解决方案3】:

    问题在于,std::vector 在内存中的某处分配了一个数组,如果该向量稍后增长,则需要将该数组移动到另一个位置。所以即使这段代码也无法编译:

    std::vector<std::condition_variable> cvvector;
    cvvector.emplace_back();
    

    解决方案是使用更通用的容器std::deque 而不是std::vectorstd::deque 从不移动为其对象分配的实际存储空间。 std::deque 通过[] 操作符对元素引用具有恒定的访问时间:

    std::deque<std::condition_variable> cvvector;
    cvvector.emplace_back();
    cvvector.emplace_back();
    std::condition_variable& cv = cvvector[1];
    

    我仍将容器称为cvvector:只要您不使用cvvector::emplace_front()cvvector::pop_front(),它的行为就像一个向量,而不是一个队列。

    【讨论】:

      【解决方案4】:

      您可以将std::condition_variable 转换为std::vector&lt;A_with_cv&gt;,方法是让向量保存对象A_with_cv,这些对象具有不复制成员std::condition_variable 的复制构造函数和复制赋值运算符。

      这是一个例子:

      // compile with: c++ -std=c++14 -o go main.cpp -pthread
      
      #include <iostream>
      #include <vector>
      #include <condition_variable>
      #include <chrono>
      #include <mutex>
      #include <thread>
      
      class A {
      public:
          A()                  {}
          A(int d) : data_{d}  {}
      
          int  data()          const { return data_; }
          void set_data(int d)       { data_ = d;    }
      private:
          int data_{0};
      };
      
      class A_with_cv : public A {
      public:
          A_with_cv(int d = 0) : A{d}
          {}
      
          A_with_cv(const A_with_cv &a) : A{static_cast<const A&>(a)} // don't copy cv_ !
          {}
      
          A_with_cv &operator=(const A_with_cv &other)
          {
              static_cast<A&>(*this) = static_cast<const A&>(other); // don't copy cv_ !
          }
      
          std::condition_variable       &cv()       { return cv_; };
          const std::condition_variable &cv() const { return cv_; };
      private:
          std::condition_variable cv_;
      };
      
      
      struct Printer {
      public:
          Printer(std::vector<A_with_cv> &vec) {
              initiate_print(vec);
          }
      
          void initiate_print(std::vector<A_with_cv> &vec) {
              for (auto it = vec.begin(); it != vec.end(); ) {
                  auto &val_ref = *it;
      
                  ++it; // increment
                  if (it != vec.end()) {
                      auto &next_ref = *it;
                      th_vec_.push_back(std::thread(
                                                    [&]() {
                                                        std::unique_lock<std::mutex> lk(mut_);
                                                        val_ref.cv().wait(lk);
                                                        std::cout << val_ref.data() << std::endl;
                                                        lk.unlock();
                                                        next_ref.cv().notify_one(); // notify next
                                                    }));
                  } else {
                      th_vec_.push_back(std::thread(
                                                    [&]() {
                                                        std::unique_lock<std::mutex> lk(mut_);
                                                        val_ref.cv().wait(lk);
                                                        std::cout << val_ref.data() << std::endl;
                                                    }));
                  }
              }
          }
      
          void wait_for_thread_completion() {
              for (auto &th : th_vec_) {
                  th.join();
              }
          }
      private:
          std::mutex mut_;
          std::vector<std::thread> th_vec_;
      };
      
      
      int main()
      {
          std::vector<A_with_cv> vec;
          vec.push_back(A_with_cv(1));
          vec.push_back(A_with_cv(2));
          vec.push_back(A_with_cv(3));
      
          Printer printer(vec);
      
          std::this_thread::sleep_for(std::chrono::milliseconds{500});
          vec[0].cv().notify_one();
      
          printer.wait_for_thread_completion();
      }
      

      但是在使用矢量时要非常小心。向量可以重新分配元素,您可能认为您正在通知条件变量,而实际上它已不存在(例如,因为您同时执行了一些 push_backs,并且对向量元素的迭代器和引用已经无效)! 因此,为此,宁愿选择不会重新分配/使元素无效的容器,例如 std::list(或 - 前提是您只在前面或后面添加元素:std::deque)等,因为这样更安全!

      使用此类容器时,不会重新分配/使元素无效,请务必使用 emplace。示例:

      #include <condition_variable>
      #include <map>
      #include <list>
      #include <vector>
      #include <deque>
      
      int main()
      {
          std::deque<std::condition_variable> deq;
          //deq.push_back(std::condition_variable());                 // does not work
          deq.emplace_back();
      
          std::list<std::condition_variable> li;
          //li.push_back(std::condition_variable());                  // does not work
          li.emplace_back();
      
          std::map<int, std::condition_variable> ma;
          //ma.insert( std::make_pair(1, std::condition_variable())); // does not work
          //ma.emplace(std::make_pair(1, std::condition_variable())); // does not work
          ma.emplace(std::piecewise_construct,
                     std::forward_as_tuple(1),
                     std::forward_as_tuple());
      
          return 0;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-07-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-17
        • 2020-11-22
        • 1970-01-01
        相关资源
        最近更新 更多