Open arekfu opened 3 years ago
To complement the issue. We ran the sandbox/performance test with "Release" and gcc 4.8.5 with the standard implementation using resize, and using the reserve/push_back pair (solution 2). The modification has been done only for non-arithmetic/non-bool types.
I attach here the relevant results for two runs each;
Another complementary information.
We have implemented Solution 2 for all relevant standard containers and update tests accordingly.
The "cereal::access" has a new method to default-construct objects on stack. All attempts to default-construct objects within cereal are now substituted by a call to this new method.
I am opening this issue on behalf of my colleague @Teloze and myself.
Currently cereal supports serialization of types without a public default constructor via
friend cereal::access
declarations. This mechanism however fails when a type without a public default constructor is used in an STL container, as in:Compiling this with gcc 5.4.0 yields
This was discussed in issue #425, where it was correctly identified that the problem stems from the fact that cereal tries to
resize
the vector before filling it, for efficiency reasons, and this operation fails if the default constructor for the type is not accessible from the STL (because it is private, for instance).We find that this issue is very restrictive and we have come up with two possible solutions.
Solution 1
There is an overload of
std::vector::resize
that takes (in our example) anA const &
as an argument and copies it in the empty slots. Now, cereal can instantiate a dummyA
object, becausecereal::access
is friend withA
; so it seems that the restriction can at least be lifted for copy-insertable types, at virtually no cost.For types that are not copy-insertable and that have no public default constructor, we have come up with a workaround that forfeits the call to
std::vector::resize
. However, the user needs to opt in voluntarily in the workaround. That gives us the chance to warn them about the performance loss in the documentation.Solution 2
Alternatively, it is possible to support vectors of types without public constructors by replacing the calls to
std::vector::resize
withstd::vector::reserve
. As long ascereal::access
is able to call the default constructor forA
, then it will work. In principle callingreserve
is slightly less efficient, becausepush_back
needs to bump up the logical size of the vector. However, we have made some performance measurements on fairly large vectors (10⁸) and we have not been able to identify any difference between callingresize
andreserve
.Would you be willing to review a PR based on any of the ideas above?
Thanks for reading! Davide @arekfu and Daniele @Teloze