Что будет "Привет, мир!" пример для "std:: ref"?
Может ли кто-нибудь дать простой пример, демонстрирующий функциональность std::ref
? Я имею в виду пример, в котором некоторые другие конструкции (например, кортежи или шаблоны типов данных) используются , только если невозможно объяснить std::ref
без них.
Я нашел два вопроса о std::ref
здесь и здесь. Но в первом случае речь идет об ошибке в компиляторе, а во втором примере использования std::ref
не содержат std::ref
, и они включают в себя кортежи и шаблоны типов данных, которые делают понимание этих примеров сложным.
Ответы
Ответ 1
Вы должны подумать об использовании std::ref
когда функция:
- принимает параметр шаблона по значению
- или копирует/перемещает ссылочный параметр пересылки, такой как
std::bind
или конструктор для std::thread
.
std::ref
является типом значения, который ведет себя как ссылка.
В этом примере демонстрируется использование std::ref
.
#include <iostream>
#include <functional>
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;
}
Выход:
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
в основном используется для инкапсуляции ссылок при использовании 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; }
где вы хотите, чтобы различные функции, запущенные в разных потоках, делили один буферный объект. Этот пример был украден из этого превосходного учебника (С++ 11 Concurrency Tutorial - часть 3: Расширенные блокировки и переменные условия (Baptiste Wicht)) (надеюсь, что я правильно сделал атрибуцию)
Ответ 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;
}
Просто еще одно использование std :: ref в main при передаче объекта Buffer
качестве ссылки для производителя и потребителя. Если std::ref
не используется, этот код не будет компилироваться.