【问题标题】:What would be a "Hello, World!" example for "std::ref"?什么是“你好,世界!” “std::ref”的例子?
【发布时间】:2013-03-09 22:55:54
【问题描述】:

有人可以举一个简单的例子来演示std::ref 的功能吗?我的意思是一个示例,其中使用了一些其他构造(如元组或数据类型模板)仅当没有它们就无法解释 std::ref

我发现了两个关于 std::ref herehere 的问题。但在第一个中,它涉及编译器中的错误,在第二个中,std::ref 的使用示例不包含std::ref,它们涉及元组和数据类型模板,这使得理解这些示例变得复杂。

【问题讨论】:

标签: c++ c++11 std ref


【解决方案1】:

你应该考虑在函数中使用std::ref

  • 按值获取模板参数
  • 复制/移动模板参数,例如std::bindstd::thread 的构造函数。

std::ref 创建一个行为类似于引用的可复制值类型。

这个例子演示了std::ref的使用。

#include <iostream>
#include <functional>
#include <thread>

void increment( int &x )
{
  ++x;
}

int main()
{
  int i = 0;

  // Here, we bind increment to a COPY of i...
  std::bind( increment, i ) ();
  //                        ^^ (...and invoke the resulting function object)

  // i is still 0, because the copy was incremented.
  std::cout << i << std::endl;

  // Now, we bind increment to std::ref(i)
  std::bind( increment, std::ref(i) ) ();
  // i has now been incremented.
  std::cout << i << std::endl;

  // The same applies for std::thread
  std::thread( increment, std::ref(i) ).join();
  std::cout << i << std::endl;
}

输出:

0
1
2

【讨论】:

  • 可能值得指出的是,std::ref 是可重新绑定的,这与传统的引用不同,如果您将其输入到模板函数中,这可能很重要。有关示例,请参见 stackoverflow.com/questions/37101301/…
【解决方案2】:
void PrintNumber(int i) {...}

int n = 4;
std::function<void()> print1 = std::bind(&PrintNumber, n);
std::function<void()> print2 = std::bind(&PrintNumber, std::ref(n));

n = 5;

print1(); //prints 4
print2(); //prints 5

std::ref主要用于在使用std::bind时封装引用(当然其他用途也可以)。

【讨论】:

    【解决方案3】:

    您可能需要 std::ref 的另一个地方是将对象传递给您希望每个线程对单个对象而不是对象的副本进行操作的线程。

    int main(){
    BoundedBuffer buffer(200);
    
    std::thread c1(consumer, 0, std::ref(buffer));
    std::thread c2(consumer, 1, std::ref(buffer));
    std::thread c3(consumer, 2, std::ref(buffer));
    std::thread p1(producer, 0, std::ref(buffer));
    std::thread p2(producer, 1, std::ref(buffer));
    
    c1.join();
    c2.join();
    c3.join();
    p1.join();
    p2.join();
    
    return 0; }
    

    您希望在不同线程中运行的各种函数共享一个缓冲区对象。这个例子是从这个优秀的教程(C++11 Concurrency Tutorial - Part 3: Advanced locking and condition variables (Baptiste Wicht) )中偷来的(希望我的归属正确)

    【讨论】:

    • 这里之所以使用std::ref,是因为thread的构造函数需要std::reference_wrapper的参数类型
    • 这不是这里的重点,但这可能存在数据竞争。
    【解决方案4】:

    //生产者消费者问题

    #include <iostream>
    #include <thread>
    #include <mutex>
    #include <deque>
    #include <condition_variable>
    using namespace std;
    
    class Buffer {
    
        std::mutex m;
        std::condition_variable cv;
        std::deque<int> queue;
        const unsigned long size = 1000;
    
        public:
        void addNum(int num) {
            std::unique_lock<std::mutex> lock(m);
            cv.wait(lock, [this]() { return queue.size() <= size; });
            queue.push_back(num);
            cout << "Pushed " << num << endl;
            lock.unlock();
            cv.notify_all();
        }
        int removeNum() {
            std::unique_lock<std::mutex> lock(m);
            cv.wait(lock, [this]() { return queue.size()>0; });
            int num = queue.back();
            queue.pop_back();
            cout << "Poped " << num << endl;
            lock.unlock();
            cv.notify_all();
            return num;
        }
    
    };
    
    void producer(int val, Buffer& buf) {
        for(int i=0; i<val; ++i){
            buf.addNum(i);
        }
    }
    
    void consumer(int val, Buffer& buf){
        for(int i=0; i<val; ++i){
            buf.removeNum();
        }
    }
    
    int main() {
        Buffer b;
        std::thread t1(producer, 1000, std::ref(b));
        std::thread t2(consumer, 1000, std::ref(b));
    
        t1.join();
        t2.join();
        return 0;
    }
    

    在传递Buffer 对象作为生产者和消费者的引用时,只是在 main 中使用 std::ref 的另一种用法。如果没有使用std::ref,那么这段代码将无法编译。

    【讨论】:

      猜你喜欢
      • 2010-11-25
      • 2010-10-16
      • 2021-11-19
      • 2015-01-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多