1

I've done quite a bit of research on the new c++11 rvalue and carried over lvalue. Here is a sample of what I have found and read:

what-does-t-double-ampersand-mean-in-c11

how-stdthread-constructor-detects-rvalue-reference

stdthread-and-rvalue-reference

I have also briefed myself on rvalue references

Move_Semantics

rvalue_references

A Proposal to Add an Rvalue Reference to the C++ Language

Specifically, regarding the std::thread constructor, I found

how-to-create-a-thread-inside-a-class-function

and used one of the answers to write some simple code

#pragma once
#ifndef CONSUMER_H
#define CONSUMER_H

#include "Mailbox.h"
#include <thread>
#include <iostream>

class Consumer
{
private:
    Mailbox mailbox;
    std::thread consumer;
public:
    Consumer(Mailbox& newMailbox);
    ~Consumer();
    void operator()() { std::cout << consumer.get_id() << "starting\n"; }
    void start();
    void run();
};

Consumer::Consumer(Mailbox& newMailbox)
{
    this->mailbox = newMailbox;
}

void Consumer::start()
{
    consumer = std::thread(&Consumer::run, this); <-- need understanding
}

#endif

Checking the `std::thread constructor

std::thread::Thread

I observe a template that uses rvalue parameters. I understand that a std::thread can be initiated through a simple example

void run(void) {std::cout << "I'm running";}

std::thread(run);

which appears straight-forward until I am inside a class whereby I need to do the following

consumer = std::thread(&Consumer::run, this); <-- need understanding

because I learned from Jonathan Wakely that run() is a non-static member function and has to be run on an object. How is the new thread supposed to know which object to call it on if you don't tell it?

This makes some sense but the need to pass by reference the class function doesn't since I have seen A a; A&& ref = A() possible. I'm super confused about rvalues and just want to understand why the code I wrote above is necessary to pass the function to std::thread.

I feel certain I also don't understand variadic templates that well either which compounds my understand of the std::thread variadic template constructor.

Community
  • 1
  • 1
Mushy
  • 2,535
  • 10
  • 33
  • 54
  • 1
    The ampersand in `consumer = std::thread(&Consumer::run, this);` has nothing to do with references. It's an address-of operator, needed to form a [pointer-to-member-function](http://en.cppreference.com/w/cpp/language/pointer#Pointers_to_member_functions) – Igor Tandetnik Oct 11 '17 at 23:40
  • @IgorTandetnik Same thing; `int age = 45; int& rage = age is a reference to age` and a reference returns a pointer but the following `int age = 45; int* page = &age; int&& sage = page;` is not true so I'm still confused. – Mushy Oct 11 '17 at 23:48
  • What do you mean by "and a reference returns a pointer"? It makes no sense to me, sorry. Neither `age` nor `rage` are pointers. And `int&& sage = page;` won't compile. – Igor Tandetnik Oct 11 '17 at 23:50
  • 1
    Best suggestion would be to go through some of the [good C++ books](https://stackoverflow.com/q/388242/2069064). If reading the `thread` constructor documentation isn't enough to explain what `thread(&Consumer::run, this)` does, we can't really help more than that. – Barry Oct 11 '17 at 23:55
  • @Barry Perhaps you can't help me. I provided many references I have read through on rvalues. It is a new concept in c++11 and its' treatment by authors like Stroustrup tend to make assumptions about what it is without explaining what it means have `var&&`. I am reading Stroustrup's C++11 Programing Language, Lippman's C++11 Primer, and various resources about the net. My understanding hasn't clicked with rvalues yet so I came to Stack for assistance. – Mushy Oct 12 '17 at 13:41
  • @IgorTandetnik From Lippman @135 Lvalues and Rvalues - _The address-of operator (R 2.3.2, p. 52) requires an lvalue operand and returns a pointer to its operand as an rvalue_ - hence `int age = 45; int* page = &age`. If my memory serves me correctly, K&R say the same thing in `The C Programming Language (ANSI @nd Edition) – Mushy Oct 12 '17 at 14:18
  • 1
    Address-of operator can also be applied to a class member, resulting in a pointer-to-member. This wouldn't, of course, be mentioned in a C textbook, seeing as C doesn't have classes (nor pointers-to-member, which are distinct from "normal" pointers to object or pointers to function). – Igor Tandetnik Oct 12 '17 at 14:23
  • I discovered something interesting to me `int&& rref = 100; int val = *&rref;` Does this imply that `rref` is a reference to a pointer and, by example, the `std::thread` constructor takes a forward to a function pointer? – Mushy Oct 13 '17 at 01:43
  • No. You are very confused. `rref` is a reference to an `int`, and `&rref` takes its address, to create a pointer to an `int`. The symbol `&` has different meanings depending on context. In `int&` or `int&&` it declares a type "reference to int", but in `&rref` or `&Class::run` it forms a pointer by taking the address of something. These are completely different. – Jonathan Wakely Oct 13 '17 at 11:17
  • @JonathanWakely Would you like to make your comment an answer and expound upon it? I'll accept your explanation because it helps my understanding. – Mushy Oct 13 '17 at 15:06

1 Answers1

4

I observe a template that uses rvalue parameters.

No, the std::thread constructor uses forwarding references, which means they can accept any type of argument and deduce either lvalue or rvalue references, depending on the argument type.

Read forwarding references and Universal References in C++11 (Scott Meyers introduced the name "universal reference" for these, but the official name is now "forwarding reference").

This makes some sense but the need to pass by reference the class function doesn't

You're confused, &Consumer::run is not a reference of any kind. The symbol & as part of a typename means a reference, but when it apepars on the left of an expression it is the "address of" operator, which forms a pointer. In this case it is forming a pointer to member function.

The expression std::thread(&Consumer::run, this) constructs a thread with two arguments, a pointer to the member function that should run in the new thread, and a pointer to the object that the member function will be called on. So in the new thread, something like this happens:

auto pointer_to_member_function = &Consumer::run;
auto pointer_to_object = this;
(pointer_to_object->.pointer_to_member_function)();

This is equivalent to running this->run()

Jonathan Wakely
  • 166,810
  • 27
  • 341
  • 521