this post was submitted on 25 Nov 2023
30 points (96.9% liked)

C++

1778 readers
2 users here now

The center for all discussion and news regarding C++.

Rules

founded 1 year ago
MODERATORS
top 22 comments
sorted by: hot top controversial new old
[–] porgamrer 10 points 1 year ago (2 children)

To me it's not really excitement so much as "oh god how do i make this ridiculous language do the correct thing".

I'm way more scared of rogue implicit copy constructors. I wonder if cppfront has any plan to fix problems like implicit copy and pessimising move.

[–] [email protected] 7 points 1 year ago (2 children)

In Rust, making something copyable is always explicit. I like that a lot.

[–] [email protected] 3 points 1 year ago (1 children)

Cpp should have done ref by default and had & for copy, but here we are.

[–] lysdexic 1 points 1 year ago

Cpp should have done ref by default and had & for copy, but here we are.

That would defeat the goal of making it backwards-compatible with C.

[–] [email protected] 3 points 1 year ago (1 children)

Copy has a very different meaning between the two languages. In rust the equivalent of a c++ copy is a clone() call for anything non trivial

[–] BatmanAoD 3 points 1 year ago (2 children)

...which is also explicit.

[–] [email protected] 2 points 1 year ago (1 children)

@BatmanAoD @Miaou It is just what you are used to.
In C++ everything is a copy. Sometimes the compiler optimizes it away. clang-tidy may help. Having a clone() is very C-like.

[–] [email protected] 1 points 1 year ago* (last edited 1 year ago)

That's a common idiom but the default behaviour is still implicit copy, which, with VLAs and no smart pointers, makes things arguably worse than in c++

[–] [email protected] 1 points 1 year ago

I thought that was obvious as I mentioned a function call, but yes indeed

[–] lysdexic 3 points 1 year ago* (last edited 1 year ago) (1 children)

To me it’s not really excitement so much as “oh god how do i make this ridiculous language do the correct thing”.

I think this all comes down to having the right mental model.

In this case, I think it helps to know that:

  • returning by value by default implies making a copy,
  • ...but if the output type supports move semantics and the function returns a temporary value (rvalue) then the language is on your side and tries to move it instead of doing a copy.
  • and here's the kicker: now the language goes the extra mile and looks after you to avoid that copy, and if your return value allows the language to apply an optimization then the language is on your side and eliminates any potential copy without you having to do anything special.

The zany behavior is that if you set up your function to push for a move (i.e., force a local variable to be treated as a temporary), the language ceases to be able to apply its optimization.

That's basically it. No real mystery.

[–] BatmanAoD 2 points 1 year ago

The parts that seem likely to cause this confusion (which I shared when I first started using C++11) are:

  • Moves in C++ are always a potentially-destructive operation on a reference, not just a memcopy.
  • Consequently, "moving" a temporary still requires having two separate instances of the type, despite that generally not being what you want, hence RVO.
  • ...but move-semantics are generally presented and understood as an "optimization", and conceptually "take the guts of this value and re-use them as a new value" is both what RVO is doing and what move-semantics are doing.
  • std::move isn't a compiler intrinsic and doesn't force a move operation; it's just a function that returns an r-value reference. So it makes it harder, not easier, for the compiler to "see through" and optimize away, even in the case where "as if" rule should make that legal.
[–] QuadriLiteral 2 points 1 year ago (2 children)

I wonder if the language could be updated so these extra std::move invocations actually become harmless? return std::move is something that I see used quite a bit.

[–] [email protected] 3 points 1 year ago (1 children)

@QuadriLiteral @lysdexic We've been looking at a paper just recently in Kona, where the author proposed to not penalize "unfortunate" uses of std::move. I think this is user friendly and you might imagine what I've been voting for.

[–] QuadriLiteral 1 points 11 months ago

That sounds great!

[–] lysdexic 1 points 1 year ago (2 children)

I wonder if the language could be updated so these extra std::move invocations actually become harmless? return std::move is something that I see used quite a bit.

These std::move invocations are harmless, as they only cast objects to their rvalue reference.

The destructive bit takes place in the type they are assigned to, as it invokes either a move constructor or a move assignment operator, and calling those implies that the object you just passed to std::move will be invalidated after the call and should not be used subsequently.

[–] QuadriLiteral 1 points 11 months ago

I mean harmless in a way that using std::move on the return type doesn't prevent RVO?

[–] [email protected] 1 points 1 year ago (1 children)

@lysdexic @QuadriLiteral Eh, no. Really. Changing the value category disables RVO

[–] lysdexic 1 points 1 year ago (1 children)

RVO

I recommend you read the thread.

[–] [email protected] 1 points 1 year ago (1 children)
[–] lysdexic 1 points 1 year ago (1 children)

It doesn't look like it, otherwise you'd be aware that the whole point of this submission is that casting return values with std::move disables RVO.

[–] [email protected] 1 points 1 year ago (1 children)

@lysdexic You claimed otherwise:
"
These std::move invocations are harmless, as they only cast objects to their rvalue reference.
"
If you were right, we wouldn't have the motivation to look at this in EWG.

[–] lysdexic 1 points 1 year ago

If you were right, we wouldn’t have the motivation to look at this in EWG.

I am right. Not benefiting from RVO does not mean you're harming anyone.

Again, I recommend you read the submission and also the discussion.