mirror of
https://github.com/USCiLab/cereal.git
synced 2025-10-18 01:45:52 +02:00
progress towards circular loads #44
Passing tests but need to look over this with valgrind some more. Potentially have some issues here, moreso with unique_ptr than shared_ptr.
This commit is contained in:
@@ -33,12 +33,15 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include <cereal/details/helpers.hpp>
|
||||||
|
|
||||||
namespace cereal
|
namespace cereal
|
||||||
{
|
{
|
||||||
//! A class that allows cereal to load smart pointers to types that have no default constructor
|
//! A class that allows cereal to load smart pointers to types that have no default constructor
|
||||||
/*! If your class does not have a default constructor, cereal will not be able
|
/*! If your class does not have a default constructor, cereal will not be able
|
||||||
to load any smart pointers to it unless you overload LoadAndAllocate
|
to load any smart pointers to it unless you overload LoadAndAllocate
|
||||||
for your class, and provide an appropriate load_and_allocate method.
|
for your class, and provide an appropriate load_and_allocate method. You can also
|
||||||
|
choose to define a member static function instead of specializing this class.
|
||||||
|
|
||||||
The specialization of LoadAndAllocate must be placed within the cereal namespace:
|
The specialization of LoadAndAllocate must be placed within the cereal namespace:
|
||||||
|
|
||||||
@@ -62,17 +65,14 @@ namespace cereal
|
|||||||
template <> struct LoadAndAllocate<MyType>
|
template <> struct LoadAndAllocate<MyType>
|
||||||
{
|
{
|
||||||
// load_and_allocate will be passed the archive that you will be loading
|
// load_and_allocate will be passed the archive that you will be loading
|
||||||
// from and should return a raw pointer to a dynamically allocated instance
|
// from as well as an allocate object which you can use as if it were the
|
||||||
// of your type.
|
// constructor for your type. cereal will handle all memory management for you.
|
||||||
//
|
|
||||||
// This will be captured by a smart pointer of some type and you need not
|
|
||||||
// worry about managing the memory
|
|
||||||
template <class Archive>
|
template <class Archive>
|
||||||
static MyType * load_and_allocate( Archive & ar )
|
static void load_and_allocate( Archive & ar, cereal::allocate<MyType> & allocate )
|
||||||
{
|
{
|
||||||
int x;
|
int x;
|
||||||
ar( x );
|
ar( x );
|
||||||
return new MyType( x );
|
allocate( x );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} // end namespace cereal
|
} // end namespace cereal
|
||||||
@@ -85,8 +85,8 @@ namespace cereal
|
|||||||
{
|
{
|
||||||
//! Called by cereal if no default constructor exists to load and allocate data simultaneously
|
//! Called by cereal if no default constructor exists to load and allocate data simultaneously
|
||||||
/*! Overloads of this should return a pointer to T and expect an archive as a parameter */
|
/*! Overloads of this should return a pointer to T and expect an archive as a parameter */
|
||||||
static void load_and_allocate(...)
|
static std::false_type load_and_allocate(...)
|
||||||
{ }
|
{ return std::false_type(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
//! A class that can be made a friend to give cereal access to non public functions
|
//! A class that can be made a friend to give cereal access to non public functions
|
||||||
@@ -147,13 +147,13 @@ namespace cereal
|
|||||||
{ t.load(ar, version); }
|
{ t.load(ar, version); }
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
static void load_and_allocate(...)
|
static std::false_type load_and_allocate(...)
|
||||||
{ }
|
{ return std::false_type(); }
|
||||||
|
|
||||||
template<class T, class Archive> inline
|
template<class T, class Archive> inline
|
||||||
static auto load_and_allocate(Archive & ar) -> decltype(T::load_and_allocate(ar))
|
static auto load_and_allocate(Archive & ar, ::cereal::allocate<T> & allocate) -> decltype(T::load_and_allocate(ar, allocate))
|
||||||
{
|
{
|
||||||
return T::load_and_allocate( ar );
|
T::load_and_allocate( ar, allocate );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -603,56 +603,19 @@ namespace cereal
|
|||||||
if(iter == itsSharedPointerMap.end())
|
if(iter == itsSharedPointerMap.end())
|
||||||
throw Exception("Error while trying to deserialize a smart pointer. Could not find id " + std::to_string(id));
|
throw Exception("Error while trying to deserialize a smart pointer. Could not find id " + std::to_string(id));
|
||||||
|
|
||||||
return iter->second.ptr;
|
return iter->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Completes registration of a shared pointer to its unique identifier
|
//! Registers a shared pointer to its unique identifier
|
||||||
/*! After a shared pointer has been loaded for the first time, it should
|
/*! After a shared pointer has been allocated for the first time, it should
|
||||||
be registered with its loaded id for future references to it.
|
be registered with its loaded id for future references to it.
|
||||||
|
|
||||||
This call will mark the shared pointer as being valid, allowing circular references
|
|
||||||
to it to properly be loaded.
|
|
||||||
|
|
||||||
@param id The unique identifier for the shared pointer
|
@param id The unique identifier for the shared pointer
|
||||||
@param ptr The actual shared pointer */
|
@param ptr The actual shared pointer */
|
||||||
inline void postRegisterSharedPointer(std::uint32_t const id, std::shared_ptr<void> ptr)
|
inline void registerSharedPointer(std::uint32_t const id, std::shared_ptr<void> ptr)
|
||||||
{
|
{
|
||||||
std::uint32_t const stripped_id = id & ~detail::msb_32bit;
|
std::uint32_t const stripped_id = id & ~detail::msb_32bit;
|
||||||
itsSharedPointerMap[stripped_id].setValid( ptr );
|
itsSharedPointerMap[stripped_id] = ptr;
|
||||||
}
|
|
||||||
|
|
||||||
//! Begins the registration process for a shared pointer to its unique identifier
|
|
||||||
/*! When a shared pointer is loaded for the first time, we initially mark its id
|
|
||||||
as being invalid (dirty) but not associated with any actual pointer. We will associate
|
|
||||||
it with a pointer after it has been fully loaded, which happens after
|
|
||||||
this pre-registration. This allows us to properly handle nested circular
|
|
||||||
references.
|
|
||||||
|
|
||||||
If the pointer has already been fully registered, we will not adjust its valid state
|
|
||||||
|
|
||||||
@param id The unique identifier for the shared pointer */
|
|
||||||
inline void preRegisterSharedPointer( std::uint32_t const id )
|
|
||||||
{
|
|
||||||
std::uint32_t const stripped_id = id & ~detail::msb_32bit;
|
|
||||||
itsSharedPointerMap[stripped_id].valid |= false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//! Checks whether an already pre or post registered shared pointer is valid
|
|
||||||
/*! @param id The unique identifier for the shared pointer
|
|
||||||
@return true if the pointer associated with the id is valid, false otherwise */
|
|
||||||
inline bool isSharedPointerValid( std::uint32_t const id )
|
|
||||||
{
|
|
||||||
std::uint32_t const stripped_id = id & ~detail::msb_32bit;
|
|
||||||
return itsSharedPointerMap[stripped_id].valid;
|
|
||||||
}
|
|
||||||
|
|
||||||
//! Associates an already registered shared pointer with a deferred load that needs to happen
|
|
||||||
/*! @param id The id of the already registered pointer
|
|
||||||
@param func The function that performs the load */
|
|
||||||
inline void pushDeferredSharedPointerLoad( std::uint32_t const id, std::function<void()> && func )
|
|
||||||
{
|
|
||||||
std::uint32_t const stripped_id = id & ~detail::msb_32bit;
|
|
||||||
itsSharedPointerMap[stripped_id].deferredLoads.emplace_back( std::move( func ) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Retrieves the string for a polymorphic type given a unique key for it
|
//! Retrieves the string for a polymorphic type given a unique key for it
|
||||||
@@ -875,44 +838,8 @@ namespace cereal
|
|||||||
//! A set of all base classes that have been serialized
|
//! A set of all base classes that have been serialized
|
||||||
std::unordered_set<traits::detail::base_class_id, traits::detail::base_class_id_hash> itsBaseClassSet;
|
std::unordered_set<traits::detail::base_class_id, traits::detail::base_class_id_hash> itsBaseClassSet;
|
||||||
|
|
||||||
//! A struct for holding shared pointer metadata
|
|
||||||
/*! Shared pointers are associated with a uniquely generated id as well as
|
|
||||||
a valid flag, the actual shared_ptr, and some number of deferred loads.
|
|
||||||
|
|
||||||
Registering a shared pointer happens in two phases: first the id is
|
|
||||||
inserted into the table and the valid flag is marked as false. The
|
|
||||||
data is then loaded, and then after being loaded into the pointer
|
|
||||||
the id is associated with this loaded data and the valid flag is set
|
|
||||||
to true.
|
|
||||||
|
|
||||||
If we ever attempt to load an id that already exists in the table before
|
|
||||||
it is set as valid, we defer the load as this is a nested load to the
|
|
||||||
same data and must be performed after the data is fully initialized
|
|
||||||
and loaded.
|
|
||||||
|
|
||||||
If we ever attempt to load an id that already exists in the table
|
|
||||||
after the data is valid, we can immediately perform that load */
|
|
||||||
struct SharedPointerMetaData
|
|
||||||
{
|
|
||||||
//! Marks this entry as valid and performs all deferred loads
|
|
||||||
inline void setValid( std::shared_ptr<void> sptr )
|
|
||||||
{
|
|
||||||
valid = true;
|
|
||||||
ptr = sptr;
|
|
||||||
|
|
||||||
for( auto & func : deferredLoads )
|
|
||||||
func();
|
|
||||||
|
|
||||||
deferredLoads.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool valid; //!< Is this shared_ptr fully loaded?
|
|
||||||
std::shared_ptr<void> ptr; //!< The actual data
|
|
||||||
std::vector<std::function<void()>> deferredLoads; //!< Deferred loads that must happen after valid
|
|
||||||
};
|
|
||||||
|
|
||||||
//! Maps from pointer ids to metadata
|
//! Maps from pointer ids to metadata
|
||||||
std::unordered_map<std::uint32_t, SharedPointerMetaData> itsSharedPointerMap;
|
std::unordered_map<std::uint32_t, std::shared_ptr<void>> itsSharedPointerMap;
|
||||||
|
|
||||||
//! Maps from name ids to names
|
//! Maps from name ids to names
|
||||||
std::unordered_map<std::uint32_t, std::string> itsPolymorphicTypeMap;
|
std::unordered_map<std::uint32_t, std::string> itsPolymorphicTypeMap;
|
||||||
|
|||||||
@@ -339,15 +339,17 @@ namespace cereal
|
|||||||
class allocate
|
class allocate
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
allocate( T * p ) : ptr( p ) {}
|
//! Allocate the type T with the given arguments
|
||||||
|
|
||||||
template <class ... Args>
|
template <class ... Args>
|
||||||
void operator()( Args && ... args )
|
void operator()( Args && ... args )
|
||||||
{
|
{
|
||||||
::operator new (ptr) T( std::forward<Args>( args )... );
|
new (ptr) T( std::forward<Args>( args )... );
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
template <class A, class B> friend struct memory_detail::LoadAndAllocateLoadWrapper;
|
||||||
|
|
||||||
|
allocate( T * p ) : ptr( p ) {}
|
||||||
allocate( allocate const & ) = delete;
|
allocate( allocate const & ) = delete;
|
||||||
allocate & operator=( allocate const & ) = delete;
|
allocate & operator=( allocate const & ) = delete;
|
||||||
|
|
||||||
|
|||||||
@@ -149,13 +149,13 @@ namespace cereal
|
|||||||
// Member load_and_allocate
|
// Member load_and_allocate
|
||||||
template<typename T, typename A>
|
template<typename T, typename A>
|
||||||
struct has_member_load_and_allocate :
|
struct has_member_load_and_allocate :
|
||||||
std::integral_constant<bool, std::is_same<decltype( access::load_and_allocate<T>( std::declval<A&>() ) ), T*>::value> {};
|
std::integral_constant<bool, std::is_same<decltype( access::load_and_allocate<T>( std::declval<A&>(), std::declval<::cereal::allocate<T>&>() ) ), void>::value> {};
|
||||||
|
|
||||||
// ######################################################################
|
// ######################################################################
|
||||||
// Non Member load_and_allocate
|
// Non Member load_and_allocate
|
||||||
template<typename T, typename A>
|
template<typename T, typename A>
|
||||||
struct has_non_member_load_and_allocate : std::integral_constant<bool,
|
struct has_non_member_load_and_allocate : std::integral_constant<bool,
|
||||||
std::is_same<decltype( LoadAndAllocate<T>::load_and_allocate( std::declval<A&>() ) ), T*>::value> {};
|
std::is_same<decltype( LoadAndAllocate<T>::load_and_allocate( std::declval<A&>(), std::declval<::cereal::allocate<T>&>() ) ), T*>::value> {};
|
||||||
|
|
||||||
// ######################################################################
|
// ######################################################################
|
||||||
// Has either a member or non member allocate
|
// Has either a member or non member allocate
|
||||||
@@ -548,7 +548,7 @@ namespace cereal
|
|||||||
struct Load
|
struct Load
|
||||||
{
|
{
|
||||||
static_assert( !sizeof(T), "Cereal detected both member and non member load_and_allocate functions!" );
|
static_assert( !sizeof(T), "Cereal detected both member and non member load_and_allocate functions!" );
|
||||||
static T * load_andor_allocate( A & /*ar*/ )
|
static T * load_andor_allocate( A & /*ar*/, allocate<T> & /*allocate*/ )
|
||||||
{ return nullptr; }
|
{ return nullptr; }
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -560,31 +560,31 @@ namespace cereal
|
|||||||
"Types must either be default constructible or define either a member or non member Construct function.\n"
|
"Types must either be default constructible or define either a member or non member Construct function.\n"
|
||||||
"Construct functions generally have the signature:\n\n"
|
"Construct functions generally have the signature:\n\n"
|
||||||
"template <class Archive>\n"
|
"template <class Archive>\n"
|
||||||
"static T * load_and_allocate(Archive & ar)\n"
|
"static void load_and_allocate(Archive & ar, cereal::allocate<T> & allocate)\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" var a;\n"
|
" var a;\n"
|
||||||
" ar & a\n"
|
" ar( a )\n"
|
||||||
" return new T(a);\n"
|
" allocate( a );\n"
|
||||||
"}\n\n" );
|
"}\n\n" );
|
||||||
static T * load_andor_allocate( A & /*ar*/ )
|
static T * load_andor_allocate()
|
||||||
{ return new T(); }
|
{ return new T(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class T, class A>
|
template <class T, class A>
|
||||||
struct Load<T, A, true, false>
|
struct Load<T, A, true, false>
|
||||||
{
|
{
|
||||||
static T * load_andor_allocate( A & ar )
|
static void load_andor_allocate( A & ar, allocate<T> & allocate )
|
||||||
{
|
{
|
||||||
return access::load_and_allocate<T>( ar );
|
access::load_and_allocate<T>( ar, allocate );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class T, class A>
|
template <class T, class A>
|
||||||
struct Load<T, A, false, true>
|
struct Load<T, A, false, true>
|
||||||
{
|
{
|
||||||
static T * load_andor_allocate( A & ar )
|
static void load_andor_allocate( A & ar, allocate<T> & allocate )
|
||||||
{
|
{
|
||||||
return LoadAndAllocate<T>::load_and_allocate( ar );
|
LoadAndAllocate<T>::load_and_allocate( ar, allocate );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|||||||
@@ -62,14 +62,16 @@ namespace cereal
|
|||||||
template <class Archive, class T>
|
template <class Archive, class T>
|
||||||
struct LoadAndAllocateLoadWrapper
|
struct LoadAndAllocateLoadWrapper
|
||||||
{
|
{
|
||||||
LoadAndAllocateLoadWrapper() = default;
|
LoadAndAllocateLoadWrapper( T * ptr ) :
|
||||||
|
allocate( ptr )
|
||||||
|
{ }
|
||||||
|
|
||||||
inline void serialize( Archive & ar )
|
inline void serialize( Archive & ar )
|
||||||
{
|
{
|
||||||
ptr = ::cereal::detail::Load<T, Archive>::load_andor_allocate( ar );
|
::cereal::detail::Load<T, Archive>::load_andor_allocate( ar, allocate );
|
||||||
}
|
}
|
||||||
|
|
||||||
T * ptr;
|
::cereal::allocate<T> allocate;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,10 +151,6 @@ namespace cereal
|
|||||||
typename std::enable_if<traits::has_load_and_allocate<T, Archive>::value, void>::type
|
typename std::enable_if<traits::has_load_and_allocate<T, Archive>::value, void>::type
|
||||||
load( Archive & ar, memory_detail::PtrWrapper<std::shared_ptr<T> &> & wrapper )
|
load( Archive & ar, memory_detail::PtrWrapper<std::shared_ptr<T> &> & wrapper )
|
||||||
{
|
{
|
||||||
// Storage type for the pointer - since we can't default construct this type,
|
|
||||||
// we'll allocate it using std::aligned_storage and use a custom deleter
|
|
||||||
using ST = typename std::aligned_storage<T>::type;
|
|
||||||
|
|
||||||
auto & ptr = wrapper.ptr;
|
auto & ptr = wrapper.ptr;
|
||||||
|
|
||||||
uint32_t id;
|
uint32_t id;
|
||||||
@@ -161,7 +159,9 @@ namespace cereal
|
|||||||
|
|
||||||
if( id & detail::msb_32bit )
|
if( id & detail::msb_32bit )
|
||||||
{
|
{
|
||||||
ar.preRegisterSharedPointer( id );
|
// Storage type for the pointer - since we can't default construct this type,
|
||||||
|
// we'll allocate it using std::aligned_storage and use a custom deleter
|
||||||
|
using ST = typename std::aligned_storage<sizeof(T)>::type;
|
||||||
|
|
||||||
// Valid flag - set to true once construction finishes
|
// Valid flag - set to true once construction finishes
|
||||||
// This prevents us from calling the destructor on
|
// This prevents us from calling the destructor on
|
||||||
@@ -170,20 +170,20 @@ namespace cereal
|
|||||||
|
|
||||||
// Allocate our storage, which we will treat as
|
// Allocate our storage, which we will treat as
|
||||||
// uninitialized until initialized with placement new
|
// uninitialized until initialized with placement new
|
||||||
ptr.reset( reinterpret_cast<Test *>( new TT() ),
|
ptr.reset( reinterpret_cast<T *>( new ST() ),
|
||||||
[=]( T * t )
|
[=]( T * t )
|
||||||
{
|
{
|
||||||
if( valid )
|
if( valid )
|
||||||
t->~Test();
|
t->~T();
|
||||||
|
|
||||||
delete reinterpret_cast<ST *>( t );
|
delete reinterpret_cast<ST *>( t );
|
||||||
} );
|
} );
|
||||||
|
|
||||||
// Register the pointer
|
// Register the pointer
|
||||||
ar.postRegisterSharedPointer( id, ptr );
|
ar.registerSharedPointer( id, ptr );
|
||||||
|
|
||||||
// Use wrapper to enter into "data" nvp of ptr_wrapper
|
// Use wrapper to enter into "data" nvp of ptr_wrapper
|
||||||
memory_detail::LoadAndAllocateLoadWrapper<Archive, T> loadWrapper;
|
memory_detail::LoadAndAllocateLoadWrapper<Archive, T> loadWrapper( ptr.get() );
|
||||||
|
|
||||||
// Call load and allocate
|
// Call load and allocate
|
||||||
ar( loadWrapper );
|
ar( loadWrapper );
|
||||||
@@ -192,13 +192,7 @@ namespace cereal
|
|||||||
*valid = true;
|
*valid = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
|
||||||
if( ar.isSharedPointerValid( id ) )
|
|
||||||
ptr = std::static_pointer_cast<T>(ar.getSharedPointer(id));
|
ptr = std::static_pointer_cast<T>(ar.getSharedPointer(id));
|
||||||
else
|
|
||||||
ar.pushDeferredSharedPointerLoad(
|
|
||||||
id, [&, id]() { ptr = std::static_pointer_cast<T>(ar.getSharedPointer(id)); } );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Loading std::shared_ptr, case when no user load and allocate (wrapper implementation)
|
//! Loading std::shared_ptr, case when no user load and allocate (wrapper implementation)
|
||||||
@@ -215,20 +209,12 @@ namespace cereal
|
|||||||
|
|
||||||
if( id & detail::msb_32bit )
|
if( id & detail::msb_32bit )
|
||||||
{
|
{
|
||||||
//ar.preRegisterSharedPointer( id );
|
ptr.reset( detail::Load<T, Archive>::load_andor_allocate() );
|
||||||
|
ar.registerSharedPointer( id, ptr );
|
||||||
ptr.reset( detail::Load<T, Archive>::load_andor_allocate( ar ) );
|
|
||||||
ar.postRegisterSharedPointer( id, ptr );
|
|
||||||
ar( *ptr );
|
ar( *ptr );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
|
||||||
//if( ar.isSharedPointerValid( id ) )
|
|
||||||
ptr = std::static_pointer_cast<T>(ar.getSharedPointer(id));
|
ptr = std::static_pointer_cast<T>(ar.getSharedPointer(id));
|
||||||
//else
|
|
||||||
// ar.pushDeferredSharedPointerLoad(
|
|
||||||
// id, [&, id]() { ptr = std::static_pointer_cast<T>(ar.getSharedPointer(id)); } );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Saving std::unique_ptr (wrapper implementation)
|
//! Saving std::unique_ptr (wrapper implementation)
|
||||||
@@ -264,10 +250,22 @@ namespace cereal
|
|||||||
|
|
||||||
if( isValid )
|
if( isValid )
|
||||||
{
|
{
|
||||||
// Use wrapper to enter into "data" nvp
|
// allocate into unique ptr to handle exceptions
|
||||||
memory_detail::LoadAndAllocateLoadWrapper<Archive, T> loadWrapper;
|
// pretend this is the real deal
|
||||||
|
// after we get it back, transfer to proper shared ptr
|
||||||
|
|
||||||
|
// Storage type for the pointer - since we can't default construct this type,
|
||||||
|
// we'll allocate it using std::aligned_storage and use a custom deleter
|
||||||
|
using ST = typename std::aligned_storage<sizeof(T)>::type;
|
||||||
|
|
||||||
|
std::unique_ptr<ST> stPtr( new ST() );
|
||||||
|
|
||||||
|
// Use wrapper to enter into "data" nvp of ptr_wrapper
|
||||||
|
memory_detail::LoadAndAllocateLoadWrapper<Archive, T> loadWrapper( reinterpret_cast<T *>( stPtr.get() ) );
|
||||||
|
|
||||||
ar( loadWrapper );
|
ar( loadWrapper );
|
||||||
ptr.reset( loadWrapper.ptr );
|
|
||||||
|
ptr.reset( stPtr.release() );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
ptr.reset( nullptr );
|
ptr.reset( nullptr );
|
||||||
@@ -286,7 +284,7 @@ namespace cereal
|
|||||||
|
|
||||||
if( isValid )
|
if( isValid )
|
||||||
{
|
{
|
||||||
ptr.reset( detail::Load<T, Archive>::load_andor_allocate( ar ) );
|
ptr.reset( detail::Load<T, Archive>::load_andor_allocate() );
|
||||||
ar( *ptr );
|
ar( *ptr );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
14
sandbox.cpp
14
sandbox.cpp
@@ -258,11 +258,12 @@ public:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
//template <class Archive>
|
template <class Archive>
|
||||||
//static NoDefaultCtor * load_and_allocate( Archive & ar )
|
static void load_and_allocate( Archive &, cereal::allocate<NoDefaultCtor> & allocate )
|
||||||
//{
|
{
|
||||||
|
allocate( 5 );
|
||||||
//return new NoDefaultCtor(5);
|
//return new NoDefaultCtor(5);
|
||||||
//}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace cereal
|
namespace cereal
|
||||||
@@ -271,9 +272,10 @@ namespace cereal
|
|||||||
struct LoadAndAllocate<NoDefaultCtor>
|
struct LoadAndAllocate<NoDefaultCtor>
|
||||||
{
|
{
|
||||||
template <class Archive>
|
template <class Archive>
|
||||||
static NoDefaultCtor * load_and_allocate( Archive & )
|
static void load_and_allocate( Archive &, cereal::allocate<NoDefaultCtor> & allocate )
|
||||||
{
|
{
|
||||||
return new NoDefaultCtor(5);
|
allocate( 5 );
|
||||||
|
//return new NoDefaultCtor(5);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1067,13 +1067,13 @@ class MemoryCycleLoadAndAllocate
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <class Archive>
|
template <class Archive>
|
||||||
static MemoryCycleLoadAndAllocate * load_and_allocate( Archive & ar )
|
static void load_and_allocate( Archive & ar, cereal::allocate<MemoryCycleLoadAndAllocate> & allocate )
|
||||||
{
|
{
|
||||||
int value;
|
int value;
|
||||||
std::shared_ptr<MemoryCycleLoadAndAllocate> ptr;
|
std::shared_ptr<MemoryCycleLoadAndAllocate> ptr;
|
||||||
|
|
||||||
ar( value, ptr );
|
ar( value, ptr );
|
||||||
return new MemoryCycleLoadAndAllocate( value, ptr );
|
allocate( value, ptr );
|
||||||
}
|
}
|
||||||
|
|
||||||
int value;
|
int value;
|
||||||
|
|||||||
Reference in New Issue
Block a user