Closed joergbrech closed 3 years ago
Ok, I figured it out. It turns out that if I add a custom copy-constructor to my expression my_expr
(I need one for my cached expression, and I used it in the example to std::cout something with each copy-ctor call), then there will be no implicitly defined non-trivial move constructor: https://en.cppreference.com/w/cpp/language/move_constructor
So in order to fix my example I need to write a custom move constructor, or explicitly add my_expr(my_expr&&) = default
: Live Code
Sorry for bothering you with this here, it took me a while to spot this one 😅
Consider the following (questionable) transform, that replaces
+
with-
:If I call
both terminals
x
andy
get copied 5 times during the transform. Intuitively I would think, that no copies are neccessary: I construct newminus
expressions that I would expect to reference the existing terminalsx
andy
.If I do the same for a sum of three terminals
I get a total of 28 copy-constructor calls.
Live Code Example
Here is a godbold example that traces the copy constructor calls.
Background
Replacing
+
with-
is useless, my real use case is implementing a caching expression. My strategy is to wrap an expression in something derived frommy_expr<boost::yap::expr_kind::if_else, SomeAppropriateHanaTuple>
and store the cached evaluation result in anstd::optional
after the first evaluation. Theif_else
is used to check wether the cache has a value, retrieve the value if it does and evaluate the wrapped expression if it doesn't. I managed to implement this and it seems to work quite nicely.Now I wanted to implement a transform that replaces any non-terminal expression with a cached version. Here I have performance issues and during debugging I noticed that I am creating a lot of copies.