Hello.
And welcome to C++ Weekly.
I'm your host, Jason Turner.
I'm available for code reviews, contracting,
and on-site training.
In this episode, I want to revisit this GNU
pure and GNU const function attributes that I talked
about several episodes back.
And there is a lot to like about them.
But you definitely have to be careful with them.
And I will explain with a demonstration here.
Now just for the record so that we all are on the same page,
the point is that you can tell the compiler that this function
has no external side effects.
And there's two different ways of doing this.
There's pure and there's const.
And they have different levels of requirements
for what you're telling the compiler as far as
how much this function is allowed to interact
with its outside environment.
But we're just going to go ahead and create a simple struct.
And it's going to have a value--
something like this.
We're going to increment the value
and return the previous version of it.
I know.
We're pre-incrementing.
We're going to increment the value
and return the new version of it.
So let's just create a simple object of type s here.
And we're going to return s.i.
So we expect that's going to return s.val.
We're going to expect that that will return 0.
And it does.
It returns 0.
And you might notice I have optimization level one turned
on at the moment.
Now I'm going to call increment value.
And you would expect that this is going to now return 1.
That's correct.
I'm going to increment it again.
It's going to return 2 and so on.
So even at optimization level one, this
all just basically goes away.
What happens if I apply this pure function attribute here
like this?
This is what it looks like.
We're now getting 0 returned from main, because we've
told the compiler, this member function increment value,
it's not going to be able to change any global state.
So the compiler is free to assume, well,
since it can't change any global state, it's impossible for it
to have changed fell.
Therefore, the answer is 0.
And so lest you think that this is just the optimizer
doing something goofy, I will take it
back to optimization level zero here.
And you can see at no point does it actually call this function
increment value.
And in fact, if we were to do something like this,
we remove the function body.
And this is the kind of trick that we often use when we're--
well, trick is a strong word--
it is the kind of technique that I often
use when I'm working with compiler explorer
specifically to say, yeah, there's
a thing here that you won't be able to optimize.
So just do what you would normally do.
And this was a 0.
And it's not calling that function at all.
So we'll take it back one more level.
And we'll remove this function pure attribute here.
And we can see that it does, in fact, call the function twice
as you would expect it to.
And we can get other interesting results here.
So I could say let I be the first value.
And then have I plus equal this.
And then return this s.val here.
And now remember, I still don't have a function body in here.
But we know because this is not a const member function
that it can manipulate the state of the object.
So I'm going to turn on optimizations 02--
let's see.
Let's do 03.
All right.
So it's calling increment value.
It's adding that value in.
It's calling increment value again.
It's moving the result into EIX-- whatever.
So this is how it's going to work
to return the value of doing these things.
So I'll put this pure function attribute on again
and see that 0 is returned.
0-- well, it's saying, well, it couldn't' t possibly have
manipulated that .val.
So let's say, OK.
Let's return I, because some integer was
returned to us twice here.
And we can see that it calls increment value.
And then it adds it to itself, effectively doubling the value.
So it's done exactly what we told it to do.
So you definitely need to be careful
if you find yourself utilizing these pure and const function
attributes that I talked about in a previous episode.
Make sure you're using it correctly.
This is a contract that the compiler is not
warning you about at all.
But it is taking it very seriously.
And you don't even necessarily have
to have optimizations turned on at all in some cases
to get, shall we say, unexpected behavior.
So thank you for watching this episode of C++ Weekly.
I hope you enjoyed it.
Be sure to subscribe.