What would be a "Hello, World!" example for "std::ref"?

Can somebody give a simple example which demonstrates the functionality of std::ref? I mean an example in which some other constructs (like tuples, or data type templates) are used only if it is impossible to explain std::ref without them.

I found two questions about std::ref here and here. But in the first one it goes about a bug in a compiler and in the second one, examples of use of std::ref do not contain std::ref and they involve tuples and data type templates which make understanding of these examples complex.

10906 次浏览

You should think of using std::ref when a function:

  • takes a template parameter by value
  • copies/moves a template parameter, such as std::bind or the constructor for std::thread.

std::ref creates a copyable value type that behaves like a reference.

This example makes demonstrable use of 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;
}

Output:

0
1
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 is mainly used to encapsulate references when using std::bind (but other uses are possible of course).

Another place where you may need std::ref is when passing objects to threads where you want each thread to operate on the single object and not a copy of the object.

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; }

where you wish various functions running in various threads to share a single buffer object. This example was stolen from this excellent tutorial ( C++11 Concurrency Tutorial - Part 3: Advanced locking and condition variables (Baptiste Wicht) ) (hope I did the attribution correctly)

// Producer Consumer Problem

#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;
}

Just another use of std::ref in main while passing Buffer object as reference in producer and consumer. If std::ref not used then this code will not compile.