Skip to content

explicit Exception copy constructor#2613

Closed
mikea wants to merge 1 commit into
v2from
maizatskyi/2026-04-02-exception-explicit-copy
Closed

explicit Exception copy constructor#2613
mikea wants to merge 1 commit into
v2from
maizatskyi/2026-04-02-exception-explicit-copy

Conversation

@mikea

@mikea mikea commented Apr 2, 2026

Copy link
Copy Markdown
Collaborator

Exception is very heavy object, implicit copy constructor is probably an oversight.

@mikea mikea requested a review from harrishancock April 2, 2026 20:31
@kentonv

kentonv commented Apr 2, 2026

Copy link
Copy Markdown
Member

Can we remove the copy constructor entirely and add a .clone() instead?

@mikea mikea marked this pull request as draft April 3, 2026 15:12
@mikea

mikea commented Apr 3, 2026

Copy link
Copy Markdown
Collaborator Author

Can we remove the copy constructor entirely and add a .clone() instead?

I updated kj::cp yesterday to support explicit copy constructors and this is what I thought we're going to use (instead of .clone()).

Is there a specific reason you'd prefer clone rather than explicit copy constructor + kj::cp(e) for brevity?

Exception is very heavy object, implicit copy constructor is probably
an oversight.
@mikea mikea force-pushed the maizatskyi/2026-04-02-exception-explicit-copy branch from e845be1 to ae2563a Compare April 3, 2026 15:18
@mikea

mikea commented Apr 3, 2026

Copy link
Copy Markdown
Collaborator Author

btw kj::cp(e) is already a very established pattern: https://github.com/search?q=repo%3Acapnproto%2Fcapnproto%20%22kj%3A%3Acp(e%22&type=code

@kentonv

kentonv commented Apr 3, 2026

Copy link
Copy Markdown
Member

Explicit constructors don't really work.

Consider what happens if you have:

kj::Vector<Exception> vec;
kj::Exception e;
vec.add(e);

You want this to fail, because add() is invoking the copy consturctor.

But add() is defined like this:

  template <typename... Params>
  T& add(Params&&... params) KJ_LIFETIMEBOUND {
    KJ_IREQUIRE(pos < endPtr, "Added too many elements to ArrayBuilder.");
    ctor(*pos, kj::fwd<Params>(params)...);
    return *pos++;
  }

That ctor() call ends up being interpreted as an explicit constructor call. So you get no error.

.clone() doesn't have this problem; it really has to be explicit. We already use the .clone() pattern in a lot of places, and I've been intending to add it to all the core types (string, array, maybe, etc.).

The use of kj::cp today is basically in all the places where the function being called wants kj::Exception&& (rvalue), and the caller wants to give it a copy. The compiler doesn't automatically invoke the copy constructor when the callee wants an rvalue, hence kj::cp is needed, but this has always been sort of a weird hack for a weird corner case.

@mikea

mikea commented Apr 3, 2026

Copy link
Copy Markdown
Collaborator Author

I see your point. It will be a bit more involved but I think we can pull it off. I will do it in two steps then: I'll add .clone() method, will migrate all downstream and then will completely remove copy constructor.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants