Suppose that we have some object, such as std::vector<int> foo
.
I know from reading the C docs on self-assignment that foo = foo
(although weird) should technically be OK since classes in C are responsible for being self-assignment safe.
However, suppose that I also have some method reverse()
that does not modify the input, but instead returns a new vector that is a reversed version of the given argument. I then perform:
foo = reverse(foo);
Would this be OK? I've gone down a pretty deep rabbit hole reading about sequence points and things like that, and TBH my brain is sort of fried now- could anybody offer a more straightforward explanation here? I know that x = x 5
where x
is of type int
is clearly fine, but I'm wondering how this changes when we're dealing with objects that allocate memory.
In addition, suppose that we had another method reverseMutate()
that does mutate the input, and then returns that reversed (mutated) original vector back. I'm even less clear whether
foo = reverseMutate(foo);
is defined behavior.
Thank you so much for the help! I promise I've tried diving into the C docs, and I'm just looking for a more straightforward explanation that doesn't make my brain hurt...
CodePudding user response:
Yes on both counts. Everything is safe.
foo = reverse(foo);
If reverse
doesn't mutate foo
, then it returns a completely unrelated vector, and that vector is assigned to foo
. Those two steps happen in that order. The result of reverse
must be fully known before operator=
is ever called on foo
, for the same reason that if we do bar(baz(1))
, the baz
call must completely terminate before bar
is ever called.
foo = reverseMutate(foo);
This one is a little more exciting but is still fine. If reverseMutate(foo)
mutates foo
and then returns it (i.e. literally return *this;
as a std::vector<int>&
), then it behaves the same as
reverseMutate(foo);
foo = foo;
i.e. it's just self-assignment in disguise, and as you've already correctly pointed out, C classes are responsible for being able to handle this case.