Skip to content

Avoid unnecessary copies of container types - #110912

Open
aaronfranke wants to merge 1 commit into
godotengine:masterfrom
aaronfranke:dont-copy-that-floppy
Open

Avoid unnecessary copies of container types#110912
aaronfranke wants to merge 1 commit into
godotengine:masterfrom
aaronfranke:dont-copy-that-floppy

Conversation

@aaronfranke

Copy link
Copy Markdown
Member

This PR was made by doing the following:

  • Change the copy constructor of all container types to explicit (except Vector).
  • Fix all of the places where that broke compiling things, including manually checking if we really need to copy there.
  • Keep only the changes that avoid copying.
  • Discard the changes that make copying explicit and return the copy constructors to normal.

This PR changes behavior by avoiding copies, which should only improve performance with no negative consequences. For each change I checked if it was good. However, it is perfectly possible that I made mistakes.

After this PR, we can follow-up with either making the copy constructor explicit or adding duplicate, see the discussion in PR #107377 for more information.

@aaronfranke aaronfranke added this to the 4.x milestone Sep 25, 2025
@aaronfranke
aaronfranke requested review from a team as code owners September 25, 2025 21:47
@aaronfranke
aaronfranke requested review from a team September 25, 2025 21:47
@aaronfranke
aaronfranke requested review from a team as code owners September 25, 2025 21:47
Comment thread core/templates/list.h Outdated
* find an element in the list,
*/
template <typename T_v>
const Element *find(const T_v &p_val) const {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a const version of List::find to support using find in const contexts.


HashMap<Vector2i, TileMapCell> err_output;
ERR_FAIL_COND_V(pattern->is_empty(), err_output);
ERR_FAIL_COND_V(pattern->is_empty(), (HashMap<Vector2i, TileMapCell>()));

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this was a copy before. I assume this was done as a separate variable to avoid the problem of commas inside macros, but there is a solution: Wrap the macro arguments in parenthesis. So in this case, the value returned by this error macro is (HashMap<Vector2i, TileMapCell>()).

@Ivorforce

Copy link
Copy Markdown
Member

Change the copy constructor of all container types to explicit (except Vector).

I'm not seeing this change, did you push this?

@aaronfranke

aaronfranke commented Sep 25, 2025

Copy link
Copy Markdown
Member Author

@Ivorforce No, please see the part of the PR description where I wrote "and return the copy constructors to normal". It's a list of things I did in order, not a list of the final changes in the PR, sorry for the confusion.

@Ivorforce

Copy link
Copy Markdown
Member

@Ivorforce No, please see the part of the PR description where I wrote "and return the copy constructors to normal". It's a list of things I did in order, not a list of the final changes in the PR, sorry for the confusion.

Aha, makes sense. Why did you return the constructors to implicit after your fixes?

@aaronfranke

Copy link
Copy Markdown
Member Author

@Ivorforce Because the rest of the changes span 100 files and I want to separate them for improved reviewability. The existing codebase of Godot has many places where implicit copy constructor is used, which all had to be changed.

@Ivorforce

Copy link
Copy Markdown
Member

Alright, that makes sense. Thanks for clearing that up!

@Ivorforce Ivorforce left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a great effort. Those implicit copies keep haunting us, and we really should be getting rid of them.

Unfortunately, this change is not without risk. Taking a reference instead of making a copy makes the caller vulnerable to changes during execution of the code that uses these variables. If the underlying data is modified, this could lead to crashes, data corruption, or subtle bugs.
Since this change is motivated and informed by a syntactical change (making the constructors explicit), rather than a profiler, I think there's too much risk of regression to make this a blanket change. I might be swayed if you go through all of the code, and make absolutely sure there is no risk of mutation regressions, but I'm not sure if this is worth it (since we don't know if any of this is in performance critical code).

If I were to make this change, I would simply make the call explicit syntactically (via e.g. List(other_list)), to keep the syntactic change agnostic to possible changes in behavior. If the code pops up in a profiler in the future, it can more easily be fixed, because the copy is explicit and therefore an obvious target for optimization.

@aaronfranke

aaronfranke commented Sep 25, 2025

Copy link
Copy Markdown
Member Author

@Ivorforce That's why I think such a change should be done early in the dev cycle, to increase the chances that any problems are caught before a release happens. Since 4.5 was just released, we have plenty of time to test before 4.6.

@Ivorforce

Copy link
Copy Markdown
Member

@Ivorforce That's why I think such a change should be done early in the dev cycle, to increase the chances that any problems are caught before a release happens. Since 4.5 was just released, we have plenty of time to test before 4.6.

That's true, but I personally wouldn't feel comfortable risking regressions over this without any tangible benefit (i.e. profiling or benchmarking performance improvements).

@aaronfranke

aaronfranke commented Sep 25, 2025

Copy link
Copy Markdown
Member Author

@Ivorforce Understandable, but then I am left stuck between a rock and a hard place:

  1. I want to allow new code to be explicit when duplication is required, and gradually migrate to this, so I proposed adding the duplicate function.
  2. You stated that we can't do that unless we migrate all existing copy constructors to duplicate for consistency.
  3. Migrating all existing copy constructor uses to either explicit or duplicate implies that everywhere we are currently using a copy constructor will change, even when the code author did not intend that.
  4. I am hesitant to change the visible intention of existing code, especially to something I am confident is incorrect (using copy constructors where none was intended).

This really just leads me back to option 1 again, adding the duplicate function without deleting the copy constructors, which is risk-free (unlike this PR) and does not destroy the intent of existing code (unlike blanket changing everything). I can update PR #107377 to add this to the rest of the container types if this is desired.

Alternatively, I would be happy with whatever course of action you propose, if you would like to make a PR yourself.

@aaronfranke
aaronfranke force-pushed the dont-copy-that-floppy branch from 41dc86d to fad5d8f Compare November 12, 2025 07:43
@aaronfranke
aaronfranke force-pushed the dont-copy-that-floppy branch from fad5d8f to e398fc5 Compare December 6, 2025 07:11
@aaronfranke
aaronfranke force-pushed the dont-copy-that-floppy branch from e398fc5 to b729ac1 Compare January 10, 2026 17:05
@aaronfranke
aaronfranke force-pushed the dont-copy-that-floppy branch from b729ac1 to 7a91348 Compare February 13, 2026 19:04
@aaronfranke
aaronfranke requested a review from a team as a code owner February 13, 2026 19:04
@Nintorch
Nintorch requested review from a team and removed request for a team February 16, 2026 18:09
@aaronfranke
aaronfranke force-pushed the dont-copy-that-floppy branch from 7a91348 to 2fe2f4b Compare February 22, 2026 06:27
@aaronfranke
aaronfranke force-pushed the dont-copy-that-floppy branch from 2fe2f4b to 0d33bb3 Compare March 30, 2026 05:28
@aaronfranke
aaronfranke force-pushed the dont-copy-that-floppy branch from 0d33bb3 to 234192c Compare May 7, 2026 04:32
@aaronfranke
aaronfranke force-pushed the dont-copy-that-floppy branch from 234192c to d9a1bfc Compare June 14, 2026 02:20
@aaronfranke
aaronfranke force-pushed the dont-copy-that-floppy branch from d9a1bfc to c05e9e8 Compare June 21, 2026 02:46
@aaronfranke
aaronfranke force-pushed the dont-copy-that-floppy branch from c05e9e8 to 043c51d Compare July 8, 2026 13:49
@aaronfranke
aaronfranke force-pushed the dont-copy-that-floppy branch from 043c51d to e84f279 Compare July 28, 2026 08:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants