Skip to content

Delete default constructor and move assignment on hash tables - #835

Merged
PointKernel merged 3 commits into
NVIDIA:devfrom
amarkdotdev:fix/delete-hash-table-move-ops
Aug 26, 2026
Merged

Delete default constructor and move assignment on hash tables#835
PointKernel merged 3 commits into
NVIDIA:devfrom
amarkdotdev:fix/delete-hash-table-move-ops

Conversation

@amarkdotdev

@amarkdotdev amarkdotdev commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

The owning hash tables (static_map, static_set, static_multimap, static_multiset, dynamic_map) defaulted both move operations. This deletes the default constructor and move assignment, and keeps move construction.

Move assignment is the hazard: impl_ = std::move(rhs.impl_) frees the still-named destination's storage on its construction stream, so refs handed out from it silently dangle with no host side signal. Move construction just transfers a unique_ptr, so refs stay valid and downstream code (e.g. cudf json_tree.cu) relies on it.

Fixes #612

Owning map/set types were accidentally move-constructible and move-assignable, which can silently transfer GPU storage. Match the copy members and disable default construction too.

Fixes NVIDIA#612

Signed-off-by: Aaron <amark@g.jct.ac.il>
@copy-pr-bot

copy-pr-bot Bot commented Aug 19, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@sleeepyjack sleeepyjack added P1: Should have Necessary but not critical type: improvement Improvement / enhancement to an existing function labels Aug 20, 2026
@sleeepyjack

Copy link
Copy Markdown
Collaborator

/ok to test 043b2a0

@PointKernel PointKernel 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.

@amarkdotdev Thanks for the contribution

Approving. Checked cudf: every cuco table is held behind a pimpl unique_ptr or as a local passed by reference, so nothing downstream breaks.

Pushed dynamic_map to your branch, which the description mentions but the diff missed.

Note bloom_filter and hyperloglog still default their move ops. Same argument applies, worth a follow-up.

@PointKernel

Copy link
Copy Markdown
Member

/ok to test 69b7cea

@sleeepyjack

Copy link
Copy Markdown
Collaborator

Was #807 considered here? It fixed the dangling allocator references specifically so that core containers are safely movable. Given that the current containers transfer pointer-owned storage without relocating it, what remaining invariant requires deleting their move operations?

@PointKernel

Copy link
Copy Markdown
Member

Pushed a change restoring the move constructor, keeping the deleted default ctor and deleted move assignment.

To answer the question directly: for move construction there is no remaining invariant. All five containers hold std::unique_ptr<impl_type>, so a move transfers a pointer, bucket_storage never relocates, and refs taken beforehand stay valid. #807 removed the last self referential state, so you are right that half of this was already solved.

Move assignment is the exception. impl_ = std::move(rhs.impl_) is reset(release()), which frees the destination's storage through aligned_deleter on its construction stream while the destination stays named and usable, so refs previously handed out from it silently point at freed memory. That is the only operation here with no host side signal, and it is what is worth deleting. This lands on the same shape as cudf::table and cudf::column.

Deleting the move constructor also broke cudf at cpp/src/io/json/json_tree.cu:694, :704 and :712, where 694 and 704 fail even without an explicit std::move because copy elision does not reach through the std::pair constructor parameter. My earlier approval note was wrong on that point, sorry. Every downstream use I found is move construction and I found no move assignment of a cuco container in any consumer or in our own tests, so this shape costs nobody a line.

Two description fixes for a follow up: X() = delete is a no op today since every ctor has two or more non defaulted leading parameters, worth keeping only as a guard against a future default argument, cf. hyperloglog.cuh:61. And the unique_ptr in tests/static_map/shared_memory_test.cu:92 documents the absence of move ops, not a hazard from moving.

@PointKernel

Copy link
Copy Markdown
Member

/ok to test a58244e

@PointKernel PointKernel changed the title Delete default/move ctor and assignment on hash tables Delete default constructor and move assignment on hash tables Aug 26, 2026
@PointKernel
PointKernel merged commit 1d538b6 into NVIDIA:dev Aug 26, 2026
23 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

P1: Should have Necessary but not critical type: improvement Improvement / enhancement to an existing function

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG]: Fix issues with hash table constructors and assignment operators.

3 participants