-
-
Notifications
You must be signed in to change notification settings - Fork 22k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add move semantics (constructor, assignment) to StringName
.
#100483
Add move semantics (constructor, assignment) to StringName
.
#100483
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Now that we are getting into territory where the performance benefit is less obvious, i think we need to start profiling to show that this actually makes a measurable difference. |
Generally I agree; not every type needs move semantics. |
Profiling is not the same as benchmarking. Profiling means finding a place in Godot that triggers this case often and checking to see that you have saved time by making this change. Remember, the end goal for every performance PR is to make Godot games run faster. We need to actually show that this change will help games run faster. |
Well, besides the 8500 uses of the If you still think it's not warranted without a specific use case, I'm sure I can find something in the codebase that is actually, practically improved by this... But is it really worth it for 14 lines of pretty trivial code? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This make sense for core data structures.
unref(); | ||
_data = p_name._data; | ||
p_name._data = nullptr; | ||
return *this; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (_data != p_name._data) {
unref();
_data = p_name._data;
p_name._data = nullptr;
}
return *this;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe assign nullptr to p_name in both cases ? Or else the caller is still valid after the call, which is fine by move standard, but could be error prone.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nullptr
cannot be assigned to the caller because the if (_data != p_name._data) {
test covers this == &p_name
- so we could accidentally be setting our own pointer to nullptr
accidentally. Besides, if we set its data to nullptr
without taking ownership of it, we would need to unref
it. move
semantics aren't guaranteed to destruct the param anyway, but they are guaranteed to keep it in a valid state.
Regarding your code change suggestion, like last time I still prefer early exit to indented blocks :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's style anyway, so any will do, but you already have the indented block :). This just remove one line.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah - just to clear it up i prefer indented blocks to be the trivial path and unindented blocks to be the important path. This principle allows you to always know which is the important path, and it helps prevent double indentations or reformats if another early exit case pops up.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's the general principle we go by, early exit is preferred
The road to bloat is paved with good intentions. potential for improvement is not the same thing as improvement. Idiomatic code isn't a benefit in itself. If a code change improves performance, then its not a burden to show that instead of just saying it. Remember, the decision of the maintainers was that we shouldn't use move semantics widely since it makes the codebase harder to understand and more difficult to attract new contributors. Optimizing for maintainability is our number one priority. So if we are going to make something harder to understand and harder to maintain, we have to justify it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
I agree with this 100%, however in this case given how very pervasive StringName is, and how often it is part of other structures, not putting move constructors and assignment operators in StringName will, in my mind, certainly prevent the compiler from being allowed to use moves at times where they would be very beneficial. I think we need them for String, StringName, our containers, core math types (using memcpy instead of 3 or 4 assignments), the use of unions makes these a weird one for the compiler probably, and variant. I think once those are in place, adding more would indeed just be useless for performance unless a very clear (profile based!) case can be made for them. |
@clayjohn does my comment address your concern? If so I'd like to see this merged so we can proceed with this sub project :) |
Yes :) Additionally, we discussed this (and the other move semantics PRs) in a maintainer meeting today and agreed that we are happy to add move semantics to most core types as long as the implementation is relatively straightforward and doesn't require changes in how the type is used outside of core. This is a bit broader than our agreement from October. |
Thanks! |
We've recently begun to introduce move semantics to
core
, for its performance benefits. Examples of functions that can benefit a lot from move semantics includeSWAP
(#100367),reduce_at
andinsert
(#100477), and simple data transfer. For more information on motivation, see #100426.