Skip to content

move confirmation_callback_t constructors out of line and fix move semantics - #1620

Open
erics118 wants to merge 7 commits into
brainboxdotcc:devfrom
erics118:callback-constructors
Open

move confirmation_callback_t constructors out of line and fix move semantics#1620
erics118 wants to merge 7 commits into
brainboxdotcc:devfrom
erics118:callback-constructors

Conversation

@erics118

@erics118 erics118 commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

TLDR: user-declared dtors were suppressing implicit moves, so the "moves" would copy data. this pr restores proper move semantics without removing the virtual dtors, and defines certain big class special members out of line for a much faster build (for me, 41.8s->12.6s)


previously, almost every data class declared a destructor (usually of the form virtual ~T() = default). the existence of this user-declared dtor suppresses the implicit move constructor/move assignment, so these "moves" have been copies.

this PR fixes it to have proper move semantics, and moves the definitions out of line to reduce codegen (they are now generated once, instead of in every TU).

all classes still keep their virtual destructors, so deriving from them and deleting through a base pointer is the same as before.

specifically:

  • json_interface only types: ban, invite, prune, dtemplate, voiceregion, voicestate, auditlog, guild_command_permissions, onboarding, application_role_connection and its nested metadata, automod_metadata
    • the virtual dtor stays, and we declare the full rule of 5 with default to get proper moves back
  • managed derived types: application, integration, stage_instance, sticker, user_identified, automod_rule
    • they already have a virtual dtor via managed, so the extra dtor decl is redundant. removing it re-enables the implicit moves.

by doing this, every confirmable_t alternative is nothrow moveable (except on msvc, see below), so confirmation_callback_t is also nothrow moveable, and the REST results and coro plumbing properly move instead of copy.

for the noexcept specs, two c++17 facts collide:

  • an out-of-line defaulted member does not get a computed exception specification: callers only see what the header declares, so the noexcept must be spelled on the declaration, and it must match what the compiler would have computed or the defaulted definition is ill-formed.
  • msvc's std::map move can throw, unlike libstdc++/libc++, so a type holding a map can't promise unconditional noexcept.

so:

  • big types: message, embed, component, interaction, interaction_response, guild, confirmation_callback_t
    • define their special members out of line for the consumer compile speedup
    • the ones with only nothrow-movable members (embed, component) declare plain noexcept
    • the ones holding std::map directly or transitively (message via attached_poll, interaction via resolved its integration-owners map and its msg, guild via voice_members, interaction_response via its message, confirmation_callback_t via confirmable_t) declare a conditional spec mirroring what the compiler would compute
      • for example, we have the line message(message&&) noexcept(std::is_nothrow_move_constructible_v<std::optional<poll>>)): nothrow on gcc/clang, potentially throwing on msvc, valid everywhere
  • smaller types: command_option, slashcommand, channel, user, welcome_screen, and all the small rule-of-5 types
    • keep in-class = default copy/move members. in-class defaulting gets the computed exception specification automatically, so the compiler produces the right spec per platform with nothing spelled out
    • virtual destructors for command_option, slashcommand, channel, user and welcome_screen still live out of line, since an out-of-line dtor is the class's key function and pins the vtable and typeinfo to a single TU.

I also ran some benchmarks by compiling my bot, to see whether this out-of-lining had benefits (avg of 3 runs):

  • before this pr: 41.8s
  • this pr, but with no out-of-lining: 38.4s
  • this pr: 12.6s

Code change checklist

  • I have ensured that all methods and functions are fully documented using doxygen style comments.
  • My code follows the coding style guide.
  • I tested that my change works before raising the PR.
  • I have ensured that I did not break any existing API calls.
  • I have not built my pull request using AI, a static analysis tool or similar without any human oversight.

@netlify

netlify Bot commented Jul 23, 2026

Copy link
Copy Markdown

Deploy Preview for dpp-dev ready!

Name Link
🔨 Latest commit a5ca5d3
🔍 Latest deploy log https://app.netlify.com/projects/dpp-dev/deploys/6a7171b4e7325b0008b65f09
😎 Deploy Preview https://deploy-preview-1620--dpp-dev.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@github-actions github-actions Bot added documentation Improvements or additions to documentation code Improvements or additions to code. labels Jul 23, 2026

@braindigitalis braindigitalis left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

needs comments, and we can't really just get rid of the destructors as it breaks the expectations of the managed base class.

Comment thread include/dpp/appcommand.h
Comment thread include/dpp/appcommand.h Outdated
Comment thread include/dpp/appcommand.h
Comment thread include/dpp/appcommand.h
Comment thread include/dpp/automod.h
Comment thread include/dpp/ban.h
Comment thread include/dpp/integration.h
Comment thread include/dpp/message.h
Comment thread include/dpp/prune.h
Comment thread include/dpp/restresults.h
declare special member functions out of line, so codegen is emitted
once
rather than in every tu
declare special members out of line for large objects
(message, embed, component, user, channel, guild, slashcommand,
interaction, command_option)
for json_interface only types (ban, invite, prune, dtemplate, voiceregion,
voicestate, auditlog, guild_command_permissions, onboarding,
application_role_connection and its nested metadata, automod_metadata)
virtual destructor has to stay, and we declare rule of 5 to ensure
proper move semantics

for managed types, (application, integration, stage_instance, sticker,
user_identified, automod_rule) the declared destructor is redundant, so
we remove it, so it supports proper move semantics

now, confirmation_callback_t is known to be nothrow moveable
bc previous unconditional noexcept doesn't work on msvc (bc std::map
move can throw, and message has a map)
@erics118
erics118 force-pushed the callback-constructors branch from 097c388 to f995dc5 Compare August 4, 2026 01:03
@erics118

erics118 commented Aug 4, 2026

Copy link
Copy Markdown
Contributor Author

ill fix docs and other stuff once i figure out what actually works

make interaction, guild out of line

welcome_screen, user in-line
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

code Improvements or additions to code. documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants