Что было бы привет, мир! пример для std::ref?

Может ли кто-нибудь привести простой пример, демонстрирующий функциональность std::ref? Я имею в виду пример, в котором некоторые другие конструкции (например, кортежи или шаблоны типов данных) используются только если без них невозможно объяснить std::ref.

Я нашел два вопроса о std::ref здесь и здесь. Но в первом речь идет об ошибке в компиляторе, а во втором примеры использования std::ref не содержат std::ref и включают кортежи и шаблоны типов данных, которые усложняют понимание этих примеров.


person Roman    schedule 20.03.2013    source источник
comment
en.cppreference.com/w/cpp/utility/functional/ref   -  person Stephan Dollberg    schedule 20.03.2013


Ответы (4)


Вам следует подумать об использовании std::ref, когда функция:

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
person Drew Dormann    schedule 20.03.2013
comment
Вероятно, стоит отметить, что std::ref можно повторно привязать, в отличие от обычной ссылки, что может иметь значение, если вы передаете ее в функцию шаблона. См. stackoverflow.com/questions/37101301/ для примера. - person Michael Anderson; 09.05.2016

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 (но, конечно, возможны и другие варианты использования).

person sbabbi    schedule 20.03.2013

Еще одно место, где вам может понадобиться 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) ) (надеюсь, я правильно указал авторство)

person bd2357    schedule 10.03.2015
comment
Причина использования std::ref здесь заключается в том, что конструктору thread требуется тип параметра std::reference_wrapper - person Deqing; 06.05.2015
comment
Это не главное здесь, но здесь возможна гонка данных. - person rjhcnf; 26.10.2020

// Проблема производителя-потребителя

#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 не используется, этот код не будет компилироваться.

person Rupesh Yadav.    schedule 22.05.2019