5.71M

Values, Objects, and References, oh my! - Nicole Mazzuca - CppCon 2017

1.

Values, Objects, and
References, oh my!
The C++ Value/Object Model, and why it matters to you

2.

Me:
• I’m a barista
• I love coffee, and especially espresso
• I’ve been programming since I was 8, in C

3.

Rules!
• First of all: ASK QUESTIONS
• This stuff is going to break your world model!
• I’ll try to go slowly
• But if you have a question, you’re probably not the only one!
• Second of all: NO CORRECTIONS
• I will sometimes simplify things
• I will not always use correct language
• Please give me space to do this

4.

The Basics

5.

What’s a value?
When people talk about “prvalues”, they mean this concept

6.

Okay… so what’s an object?
An object is storage where a value lives

7.

Value Semantics
In the beginning, there were value semantics.

8.

Reference Semantics
Then there were reference semantics

9.

What about pointers?
Pointers in C++ are an interesting case. They do three things:
• They are the value representation of an lvalue.
• They represent an lvalue, OR `nullptr`
• They allow arithmetic on the address.

10.

Let’s talk about product types!

11.

What is a product type?
• A product type is a type that includes the values of different types
• An example of this is the `struct` type in C and C++
• Another is `std::tuple`
• A value of a product type is represented by the values of each of its members

12.

Okay, so product types
That makes sense.
Each type’s value representation is included in the value representation of the product type.
Wait, what about const and reference members?

13.

Okay, so product types
That doesn’t fit into our world! Oh noes!
References don’t have a value representation – they aren’t values!
Const types are weird! You can’t assign to them!
Well, let’s think about this logically.

14.

Values of Product Type
So, let’s look at const members first.
If we think of product types in terms of values, they make total sense! If you have a value of
this product type, it includes the const member, and if you put it in an object, you can’t
mutate that member. Cool!
Wait, what about assignment?

15.

Assignment
What is assignment?
In C++, it’s the call to `operator=`. But conceptually, what is it?
I’d assert, it’s the syntax for giving an object a new value.
This means that the new value has nothing to do with the old value.

16.

Assignment

17.

Assignment

18.

Assignment
Anyone have an issue with that?
(seriously, if that doesn’t make sense to you, raise your hand)

19.

Assignment
So if this is true… why are const and reference members kinda terrible?

20.

const
(and why it’s kinda bad)

21.

What is const?

22.

What is const?

23.

What is const?
side note: thanks Eelis!

24.

What is const?
Apparently it’s a kind of object.
Wait… what about pointers to const?

25.

What is const?
Apparently it’s a kind of object.
Wait… what about pointers to const?
… oh

26.

What is const?
Apparently it’s a kind of object.
Wait… what about pointers to const?
… yikes

27.

What’s this all mean?
You can pretend that a pointer to object is a pointer to const object.
Okay, that’s insane. Let’s ignore the complexity of the standard wording for a bit, and try
to see what they actually want to have happen here.
They want to be able to use references and pointers to const objects as const views of nonconst objects
Wow this got wordy all of a sudden.

28.

Okay, back to product types
The standard cares about const objects. It also cares about const subobjects.
This sucks.
We can’t define our `operator=`s how we’d expect them to be defined.
When you have a const subobject, you *can’t* update it (without it probably being
undefined behavior)
This is a consequence of object-obsessed committee members.
Wait, if `const` has these issues… what about reference members?

29.

Reference Members
(And why they’re cool, but bad)

30.

What’s the deal with reference members?
The standard pretty much pretends they don’t exist. There is no standard behavior with
regard to them – the standard only allows implementations to assume they don’t get
rebound.
This behavior is, as you’ll see, not… great.

31.

How do they work in the real model
So, a reference is an alias of an object. It isn’t a value.
A value of class type is a… well, a value.
How does a value having an alias work?
Well, if you’re anything like me, you expect that the value owns an alias.
C++ is not that way.
The object owns the alias.

32.

Wait, what’s that mean?
It means that if you change the value, *you cannot rebind any reference members*
This breaks, completely, the idea:

33.

How do we fix it?
We pretend that that wording doesn’t exist, and just never use reference or const members.
This is my favorite solution.
Then we fix the standard to make references in structs rebindable, and consts in structs
mutable.
(there are apparently people working on this)
Now, given this mental model, let’s look at people’s favorite data structure!

34.

optional<T&>
(and why it makes total sense and only has one sane way of working)

35.

Why’s it make sense?
Well, let’s put it into our model.
`optional<T>` is a value that includes an optional value.
`optional<T&>` is a value that includes an optional reference.
Same as with reference members of struct types, assigning a new value to the optional
should, you know, actually assign a new value.
Rebind semantics are the only ones that make any sense.

36.

Finally, some real prvalues!
(and why they’re amazing)

37.

Before C++17

38.

After C++17
(it turns out showing that a compiler error didn’t happen is kinda boring)
Basically, how assignment works was changed slightly.

39.

Other interesting issues of prvalues
i.e., how’s an rvalue reference work?

40.

How’s this work?

41.

How’s this work?
First, we create an overload set for `foo`:
• foo(string&&)
• (there’s only one overload)

42.

How’s this work?
First, we create an overload set for `foo`:
• foo(string&&)
Second, we attempt to convert the
`char const(&)[14]`
into a `string`. Let’s look at the implicit conversions on
string, and build another overload set!
• string(size_t, char)
• string(string const&, size_t)
• …
• string(char const*)
• Oh look! A `char const*`! I can turn into that!

43.

How’s this work?
First, we create an overload set for `foo`:
• foo(string&&)
`char const(&)[14]` -> `string(char const*)`
Now, we call the `string` constructor; how do we turn
this string prvalue that we’ve created into a
`string&&`, like `foo` requests?

44.

Wait for it……

45.

Temporary Objects!
We create an object on the stack, and then pass a reference to *that* to `foo`.

46.

Temporary Objects!

47.

Const Prvalues
A Rant

48.

Const Prvalues

49.

Const Prvalues

50.

Changes I’d like to see
(and why I’m awesome)

51.

Just a few
• Make const and reference members more normal
• Make const prvalues not a thing
• A rule that I must be given coffee as a matter of course during the meeting

52.

Questions?
English     Русский Правила