mirror of
https://github.com/USCiLab/cereal.git
synced 2025-10-18 01:45:52 +02:00
Renaming load_and_allocate to load_and_construct
Anything associated this that used the verb allocate has been replaced with construct closes #59
This commit is contained in:
@@ -39,11 +39,11 @@ 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 LoadAndConstruct
|
||||||
for your class, and provide an appropriate load_and_allocate method. You can also
|
for your class, and provide an appropriate load_and_construct method. You can also
|
||||||
choose to define a member static function instead of specializing this class.
|
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 LoadAndConstruct must be placed within the cereal namespace:
|
||||||
|
|
||||||
@code{.cpp}
|
@code{.cpp}
|
||||||
struct MyType
|
struct MyType
|
||||||
@@ -59,20 +59,20 @@ namespace cereal
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Provide a specialization for LoadAndAllocate for your type
|
// Provide a specialization for LoadAndConstruct for your type
|
||||||
namespace cereal
|
namespace cereal
|
||||||
{
|
{
|
||||||
template <> struct LoadAndAllocate<MyType>
|
template <> struct LoadAndConstruct<MyType>
|
||||||
{
|
{
|
||||||
// load_and_allocate will be passed the archive that you will be loading
|
// load_and_construct will be passed the archive that you will be loading
|
||||||
// from as well as an allocate object which you can use as if it were the
|
// from as well as a construct object which you can use as if it were the
|
||||||
// constructor for your type. cereal will handle all memory management for you.
|
// constructor for your type. cereal will handle all memory management for you.
|
||||||
template <class Archive>
|
template <class Archive>
|
||||||
static void load_and_allocate( Archive & ar, cereal::allocate<MyType> & allocate )
|
static void load_and_construct( Archive & ar, cereal::construct<MyType> & construct )
|
||||||
{
|
{
|
||||||
int x;
|
int x;
|
||||||
ar( x );
|
ar( x );
|
||||||
allocate( x );
|
construct( x );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} // end namespace cereal
|
} // end namespace cereal
|
||||||
@@ -81,30 +81,30 @@ namespace cereal
|
|||||||
Please note that just as in using external serialization functions, you cannot get
|
Please note that just as in using external serialization functions, you cannot get
|
||||||
access to non-public members of your class by befriending cereal::access. If you
|
access to non-public members of your class by befriending cereal::access. If you
|
||||||
have the ability to modify the class you wish to serialize, it is recommended that you
|
have the ability to modify the class you wish to serialize, it is recommended that you
|
||||||
use member serialize functions and a static member load_and_allocate function.
|
use member serialize functions and a static member load_and_construct function.
|
||||||
|
|
||||||
@tparam T The type to specialize for
|
@tparam T The type to specialize for
|
||||||
@ingroup Access */
|
@ingroup Access */
|
||||||
template <class T>
|
template <class T>
|
||||||
struct LoadAndAllocate
|
struct LoadAndConstruct
|
||||||
{
|
{
|
||||||
//! 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 construct 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 std::false_type load_and_allocate(...)
|
static std::false_type load_and_construct(...)
|
||||||
{ return std::false_type(); }
|
{ return std::false_type(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
// forward decl for allocate
|
// forward decl for construct
|
||||||
//! @cond PRIVATE_NEVERDEFINED
|
//! @cond PRIVATE_NEVERDEFINED
|
||||||
namespace memory_detail{ template <class Ar, class T> struct LoadAndAllocateLoadWrapper; }
|
namespace memory_detail{ template <class Ar, class T> struct LoadAndConstructLoadWrapper; }
|
||||||
//! @endcond
|
//! @endcond
|
||||||
|
|
||||||
//! Used to allocate types with no default constructor
|
//! Used to construct types with no default constructor
|
||||||
/*! When serializing a type that has no default constructor, cereal
|
/*! When serializing a type that has no default constructor, cereal
|
||||||
will attempt to call either the class static function load_and_allocate
|
will attempt to call either the class static function load_and_construct
|
||||||
or the appropriate template specialization of LoadAndAllocate. cereal
|
or the appropriate template specialization of LoadAndConstruct. cereal
|
||||||
will pass that function a reference to the archive as well as a reference
|
will pass that function a reference to the archive as well as a reference
|
||||||
to an allocate object which should be used to perform the allocation once
|
to a construct object which should be used to perform the allocation once
|
||||||
data has been appropriately loaded.
|
data has been appropriately loaded.
|
||||||
|
|
||||||
@code{.cpp}
|
@code{.cpp}
|
||||||
@@ -124,21 +124,21 @@ namespace cereal
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <class Archive>
|
template <class Archive>
|
||||||
static void load_and_allocate( Archive & ar, cereal::allocate<MyType> & allocate )
|
static void load_and_construct( Archive & ar, cereal::construct<MyType> & construct )
|
||||||
{
|
{
|
||||||
int x, y;
|
int x, y;
|
||||||
ar( x, y );
|
ar( x, y );
|
||||||
|
|
||||||
// use allocate object to initialize with loaded data
|
// use construct object to initialize with loaded data
|
||||||
allocate( x, y );
|
construct( x, y );
|
||||||
|
|
||||||
// access to member variables and functions via -> operator
|
// access to member variables and functions via -> operator
|
||||||
ar( allocate->notInConstructor );
|
ar( construct->notInConstructor );
|
||||||
|
|
||||||
// could also do the above section by:
|
// could also do the above section by:
|
||||||
double z;
|
double z;
|
||||||
ar( z );
|
ar( z );
|
||||||
allocate->notInConstructor = z;
|
construct->notInConstructor = z;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@endcode
|
@endcode
|
||||||
@@ -146,10 +146,10 @@ namespace cereal
|
|||||||
@tparam T The class type being serialized
|
@tparam T The class type being serialized
|
||||||
*/
|
*/
|
||||||
template <class T>
|
template <class T>
|
||||||
class allocate
|
class construct
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
//! Allocate and initialize the type T with the given arguments
|
//! Construct and initialize the type T with the given arguments
|
||||||
/*! This will forward all arguments to the underlying type T,
|
/*! This will forward all arguments to the underlying type T,
|
||||||
calling an appropriate constructor.
|
calling an appropriate constructor.
|
||||||
|
|
||||||
@@ -162,7 +162,7 @@ namespace cereal
|
|||||||
void operator()( Args && ... args )
|
void operator()( Args && ... args )
|
||||||
{
|
{
|
||||||
if( itsValid )
|
if( itsValid )
|
||||||
throw Exception("Attempting to allocate an already initialized object");
|
throw Exception("Attempting to construct an already initialized object");
|
||||||
|
|
||||||
new (itsPtr) T( std::forward<Args>( args )... );
|
new (itsPtr) T( std::forward<Args>( args )... );
|
||||||
itsValid = true;
|
itsValid = true;
|
||||||
@@ -183,7 +183,7 @@ namespace cereal
|
|||||||
|
|
||||||
//! Returns a raw pointer to the initialized underlying object
|
//! Returns a raw pointer to the initialized underlying object
|
||||||
/*! This is mainly intended for use with passing an instance of
|
/*! This is mainly intended for use with passing an instance of
|
||||||
an allocated object to cereal::base_class.
|
a constructed object to cereal::base_class.
|
||||||
|
|
||||||
It is strongly recommended to avoid using this function in
|
It is strongly recommended to avoid using this function in
|
||||||
any other circumstance.
|
any other circumstance.
|
||||||
@@ -195,11 +195,11 @@ namespace cereal
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template <class A, class B> friend struct ::cereal::memory_detail::LoadAndAllocateLoadWrapper;
|
template <class A, class B> friend struct ::cereal::memory_detail::LoadAndConstructLoadWrapper;
|
||||||
|
|
||||||
allocate( T * p ) : itsPtr( p ), itsValid( false ) {}
|
construct( T * p ) : itsPtr( p ), itsValid( false ) {}
|
||||||
allocate( allocate const & ) = delete;
|
construct( construct const & ) = delete;
|
||||||
allocate & operator=( allocate const & ) = delete;
|
construct & operator=( construct const & ) = delete;
|
||||||
|
|
||||||
T * itsPtr;
|
T * itsPtr;
|
||||||
bool itsValid;
|
bool itsValid;
|
||||||
@@ -263,13 +263,13 @@ namespace cereal
|
|||||||
{ t.load(ar, version); }
|
{ t.load(ar, version); }
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
static std::false_type load_and_allocate(...)
|
static std::false_type load_and_construct(...)
|
||||||
{ return std::false_type(); }
|
{ return std::false_type(); }
|
||||||
|
|
||||||
template<class T, class Archive> inline
|
template<class T, class Archive> inline
|
||||||
static auto load_and_allocate(Archive & ar, ::cereal::allocate<T> & allocate) -> decltype(T::load_and_allocate(ar, allocate))
|
static auto load_and_construct(Archive & ar, ::cereal::construct<T> & construct) -> decltype(T::load_and_construct(ar, construct))
|
||||||
{
|
{
|
||||||
T::load_and_allocate( ar, allocate );
|
T::load_and_construct( ar, construct );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -145,22 +145,22 @@ namespace cereal
|
|||||||
struct has_non_member_versioned_##name : std::integral_constant<bool, detail::has_non_member_versioned_##name##_impl<T, A>::value> {}
|
struct has_non_member_versioned_##name : std::integral_constant<bool, detail::has_non_member_versioned_##name##_impl<T, A>::value> {}
|
||||||
|
|
||||||
// ######################################################################
|
// ######################################################################
|
||||||
// Member load_and_allocate
|
// Member load_and_construct
|
||||||
template<typename T, typename A>
|
template<typename T, typename A>
|
||||||
struct has_member_load_and_allocate :
|
struct has_member_load_and_construct :
|
||||||
std::integral_constant<bool, std::is_same<decltype( access::load_and_allocate<T>( std::declval<A&>(), std::declval< ::cereal::allocate<T>&>() ) ), void>::value> {};
|
std::integral_constant<bool, std::is_same<decltype( access::load_and_construct<T>( std::declval<A&>(), std::declval< ::cereal::construct<T>&>() ) ), void>::value> {};
|
||||||
|
|
||||||
// ######################################################################
|
// ######################################################################
|
||||||
// Non Member load_and_allocate
|
// Non Member load_and_construct
|
||||||
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_construct : std::integral_constant<bool,
|
||||||
std::is_same<decltype( LoadAndAllocate<T>::load_and_allocate( std::declval<A&>(), std::declval< ::cereal::allocate<T>&>() ) ), void>::value> {};
|
std::is_same<decltype( LoadAndConstruct<T>::load_and_construct( std::declval<A&>(), std::declval< ::cereal::construct<T>&>() ) ), void>::value> {};
|
||||||
|
|
||||||
// ######################################################################
|
// ######################################################################
|
||||||
// Has either a member or non member allocate
|
// Has either a member or non member allocate
|
||||||
template<typename T, typename A>
|
template<typename T, typename A>
|
||||||
struct has_load_and_allocate : std::integral_constant<bool,
|
struct has_load_and_construct : std::integral_constant<bool,
|
||||||
has_member_load_and_allocate<T, A>::value || has_non_member_load_and_allocate<T, A>::value>
|
has_member_load_and_construct<T, A>::value || has_non_member_load_and_construct<T, A>::value>
|
||||||
{ };
|
{ };
|
||||||
|
|
||||||
// ######################################################################
|
// ######################################################################
|
||||||
@@ -580,47 +580,47 @@ namespace cereal
|
|||||||
// ######################################################################
|
// ######################################################################
|
||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
template <class T, class A, bool Member = traits::has_member_load_and_allocate<T, A>::value, bool NonMember = traits::has_non_member_load_and_allocate<T, A>::value>
|
template <class T, class A, bool Member = traits::has_member_load_and_construct<T, A>::value, bool NonMember = traits::has_non_member_load_and_construct<T, A>::value>
|
||||||
struct Load
|
struct Construct
|
||||||
{
|
{
|
||||||
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_construct functions!" );
|
||||||
static T * load_andor_allocate( A & /*ar*/, allocate<T> & /*allocate*/ )
|
static T * load_andor_construct( A & /*ar*/, construct<T> & /*construct*/ )
|
||||||
{ return nullptr; }
|
{ return nullptr; }
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class T, class A>
|
template <class T, class A>
|
||||||
struct Load<T, A, false, false>
|
struct Construct<T, A, false, false>
|
||||||
{
|
{
|
||||||
static_assert( std::is_default_constructible<T>::value,
|
static_assert( std::is_default_constructible<T>::value,
|
||||||
"Trying to serialize a an object with no default constructor.\n\n"
|
"Trying to serialize a an object with no default constructor.\n\n"
|
||||||
"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 void load_and_allocate(Archive & ar, cereal::allocate<T> & allocate)\n"
|
"static void load_and_construct(Archive & ar, cereal::construct<T> & construct)\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" var a;\n"
|
" var a;\n"
|
||||||
" ar( a )\n"
|
" ar( a )\n"
|
||||||
" allocate( a );\n"
|
" construct( a );\n"
|
||||||
"}\n\n" );
|
"}\n\n" );
|
||||||
static T * load_andor_allocate()
|
static T * load_andor_construct()
|
||||||
{ return new T(); }
|
{ return new T(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class T, class A>
|
template <class T, class A>
|
||||||
struct Load<T, A, true, false>
|
struct Construct<T, A, true, false>
|
||||||
{
|
{
|
||||||
static void load_andor_allocate( A & ar, allocate<T> & allocate )
|
static void load_andor_construct( A & ar, construct<T> & construct )
|
||||||
{
|
{
|
||||||
access::load_and_allocate<T>( ar, allocate );
|
access::load_and_construct<T>( ar, construct );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class T, class A>
|
template <class T, class A>
|
||||||
struct Load<T, A, false, true>
|
struct Construct<T, A, false, true>
|
||||||
{
|
{
|
||||||
static void load_andor_allocate( A & ar, allocate<T> & allocate )
|
static void load_andor_construct( A & ar, construct<T> & construct )
|
||||||
{
|
{
|
||||||
LoadAndAllocate<T>::load_and_allocate( ar, allocate );
|
LoadAndConstruct<T>::load_and_construct( ar, construct );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|||||||
@@ -56,26 +56,26 @@ namespace cereal
|
|||||||
return {std::forward<T>(t)};
|
return {std::forward<T>(t)};
|
||||||
}
|
}
|
||||||
|
|
||||||
//! A struct that acts as a wrapper around calling load_andor_allocate
|
//! A struct that acts as a wrapper around calling load_andor_construct
|
||||||
/*! The purpose of this is to allow a load_and_allocate call to properly enter into the
|
/*! The purpose of this is to allow a load_and_construct call to properly enter into the
|
||||||
'data' NVP of the ptr_wrapper
|
'data' NVP of the ptr_wrapper
|
||||||
@internal */
|
@internal */
|
||||||
template <class Archive, class T>
|
template <class Archive, class T>
|
||||||
struct LoadAndAllocateLoadWrapper
|
struct LoadAndConstructLoadWrapper
|
||||||
{
|
{
|
||||||
LoadAndAllocateLoadWrapper( T * ptr ) :
|
LoadAndConstructLoadWrapper( T * ptr ) :
|
||||||
allocate( ptr )
|
construct( ptr )
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
inline void serialize( Archive & ar )
|
inline void serialize( Archive & ar )
|
||||||
{
|
{
|
||||||
::cereal::detail::Load<T, Archive>::load_andor_allocate( ar, allocate );
|
::cereal::detail::Construct<T, Archive>::load_andor_construct( ar, construct );
|
||||||
}
|
}
|
||||||
|
|
||||||
::cereal::allocate<T> allocate;
|
::cereal::construct<T> construct;
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Performs loading and allocation for a shared pointer that is NOT derived from
|
//! Performs loading and construction for a shared pointer that is NOT derived from
|
||||||
//! std::enable_shared_from_this
|
//! std::enable_shared_from_this
|
||||||
/*! This is the typical case, where we simply pass the load wrapper to the
|
/*! This is the typical case, where we simply pass the load wrapper to the
|
||||||
archive
|
archive
|
||||||
@@ -84,15 +84,15 @@ namespace cereal
|
|||||||
@param ptr Raw pointer held by the shared_ptr
|
@param ptr Raw pointer held by the shared_ptr
|
||||||
@internal */
|
@internal */
|
||||||
template <class Archive, class T> inline
|
template <class Archive, class T> inline
|
||||||
void loadAndAllocateSharedPtr( Archive & ar, T * ptr, std::false_type /* has_shared_from_this */ )
|
void loadAndConstructSharedPtr( Archive & ar, T * ptr, std::false_type /* has_shared_from_this */ )
|
||||||
{
|
{
|
||||||
memory_detail::LoadAndAllocateLoadWrapper<Archive, T> loadWrapper( ptr );
|
memory_detail::LoadAndConstructLoadWrapper<Archive, T> loadWrapper( ptr );
|
||||||
ar( _CEREAL_NVP("data", loadWrapper) );
|
ar( _CEREAL_NVP("data", loadWrapper) );
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Performs loading and allocation for a shared pointer that is derived from
|
//! Performs loading and construction for a shared pointer that is derived from
|
||||||
//! std::enable_shared_from_this
|
//! std::enable_shared_from_this
|
||||||
/*! This special case is necessary because when a user uses load_and_allocate,
|
/*! This special case is necessary because when a user uses load_and_construct,
|
||||||
the weak_ptr (or whatever implementation defined variant) that allows
|
the weak_ptr (or whatever implementation defined variant) that allows
|
||||||
enable_shared_from_this to function correctly will not be initialized properly.
|
enable_shared_from_this to function correctly will not be initialized properly.
|
||||||
|
|
||||||
@@ -110,9 +110,9 @@ namespace cereal
|
|||||||
@param ptr Raw pointer held by the shared_ptr
|
@param ptr Raw pointer held by the shared_ptr
|
||||||
@internal */
|
@internal */
|
||||||
template <class Archive, class T> inline
|
template <class Archive, class T> inline
|
||||||
void loadAndAllocateSharedPtr( Archive & ar, T * ptr, std::true_type /* has_shared_from_this */ )
|
void loadAndConstructSharedPtr( Archive & ar, T * ptr, std::true_type /* has_shared_from_this */ )
|
||||||
{
|
{
|
||||||
memory_detail::LoadAndAllocateLoadWrapper<Archive, T> loadWrapper( ptr );
|
memory_detail::LoadAndConstructLoadWrapper<Archive, T> loadWrapper( ptr );
|
||||||
|
|
||||||
// typedefs for parent type and storage type
|
// typedefs for parent type and storage type
|
||||||
using BaseType = typename ::cereal::traits::get_shared_from_this_base<T>::type;
|
using BaseType = typename ::cereal::traits::get_shared_from_this_base<T>::type;
|
||||||
@@ -143,7 +143,7 @@ namespace cereal
|
|||||||
ar( _CEREAL_NVP("ptr_wrapper", memory_detail::make_ptr_wrapper( ptr )) );
|
ar( _CEREAL_NVP("ptr_wrapper", memory_detail::make_ptr_wrapper( ptr )) );
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Loading std::shared_ptr, case when no user load and allocate for non polymorphic types
|
//! Loading std::shared_ptr, case when no user load and construct for non polymorphic types
|
||||||
template <class Archive, class T> inline
|
template <class Archive, class T> inline
|
||||||
typename std::enable_if<!std::is_polymorphic<T>::value, void>::type
|
typename std::enable_if<!std::is_polymorphic<T>::value, void>::type
|
||||||
load( Archive & ar, std::shared_ptr<T> & ptr )
|
load( Archive & ar, std::shared_ptr<T> & ptr )
|
||||||
@@ -178,7 +178,7 @@ namespace cereal
|
|||||||
ar( _CEREAL_NVP("ptr_wrapper", memory_detail::make_ptr_wrapper( ptr )) );
|
ar( _CEREAL_NVP("ptr_wrapper", memory_detail::make_ptr_wrapper( ptr )) );
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Loading std::unique_ptr, case when user provides load_and_allocate for non polymorphic types
|
//! Loading std::unique_ptr, case when user provides load_and_construct for non polymorphic types
|
||||||
template <class Archive, class T, class D> inline
|
template <class Archive, class T, class D> inline
|
||||||
typename std::enable_if<!std::is_polymorphic<T>::value, void>::type
|
typename std::enable_if<!std::is_polymorphic<T>::value, void>::type
|
||||||
load( Archive & ar, std::unique_ptr<T, D> & ptr )
|
load( Archive & ar, std::unique_ptr<T, D> & ptr )
|
||||||
@@ -205,10 +205,10 @@ namespace cereal
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Loading std::shared_ptr, case when user load and allocate (wrapper implementation)
|
//! Loading std::shared_ptr, case when user load and construct (wrapper implementation)
|
||||||
/*! @internal */
|
/*! @internal */
|
||||||
template <class Archive, class T> inline
|
template <class Archive, class T> inline
|
||||||
typename std::enable_if<traits::has_load_and_allocate<T, Archive>::value, void>::type
|
typename std::enable_if<traits::has_load_and_construct<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 )
|
||||||
{
|
{
|
||||||
auto & ptr = wrapper.ptr;
|
auto & ptr = wrapper.ptr;
|
||||||
@@ -243,7 +243,7 @@ namespace cereal
|
|||||||
ar.registerSharedPointer( id, ptr );
|
ar.registerSharedPointer( id, ptr );
|
||||||
|
|
||||||
// Perform the actual loading and allocation
|
// Perform the actual loading and allocation
|
||||||
memory_detail::loadAndAllocateSharedPtr( ar, ptr.get(), typename ::cereal::traits::has_shared_from_this<T>::type() );
|
memory_detail::loadAndConstructSharedPtr( ar, ptr.get(), typename ::cereal::traits::has_shared_from_this<T>::type() );
|
||||||
|
|
||||||
// Mark pointer as valid (initialized)
|
// Mark pointer as valid (initialized)
|
||||||
*valid = true;
|
*valid = true;
|
||||||
@@ -252,10 +252,10 @@ namespace cereal
|
|||||||
ptr = std::static_pointer_cast<T>(ar.getSharedPointer(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 construct (wrapper implementation)
|
||||||
/*! @internal */
|
/*! @internal */
|
||||||
template <class Archive, class T> inline
|
template <class Archive, class T> inline
|
||||||
typename std::enable_if<!traits::has_load_and_allocate<T, Archive>::value, void>::type
|
typename std::enable_if<!traits::has_load_and_construct<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 )
|
||||||
{
|
{
|
||||||
auto & ptr = wrapper.ptr;
|
auto & ptr = wrapper.ptr;
|
||||||
@@ -266,7 +266,7 @@ namespace cereal
|
|||||||
|
|
||||||
if( id & detail::msb_32bit )
|
if( id & detail::msb_32bit )
|
||||||
{
|
{
|
||||||
ptr.reset( detail::Load<T, Archive>::load_andor_allocate() );
|
ptr.reset( detail::Construct<T, Archive>::load_andor_construct() );
|
||||||
ar.registerSharedPointer( id, ptr );
|
ar.registerSharedPointer( id, ptr );
|
||||||
ar( _CEREAL_NVP("data", *ptr) );
|
ar( _CEREAL_NVP("data", *ptr) );
|
||||||
}
|
}
|
||||||
@@ -294,10 +294,10 @@ namespace cereal
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Loading std::unique_ptr, case when user provides load_and_allocate (wrapper implementation)
|
//! Loading std::unique_ptr, case when user provides load_and_construct (wrapper implementation)
|
||||||
/*! @internal */
|
/*! @internal */
|
||||||
template <class Archive, class T, class D> inline
|
template <class Archive, class T, class D> inline
|
||||||
typename std::enable_if<traits::has_load_and_allocate<T, Archive>::value, void>::type
|
typename std::enable_if<traits::has_load_and_construct<T, Archive>::value, void>::type
|
||||||
load( Archive & ar, memory_detail::PtrWrapper<std::unique_ptr<T, D> &> & wrapper )
|
load( Archive & ar, memory_detail::PtrWrapper<std::unique_ptr<T, D> &> & wrapper )
|
||||||
{
|
{
|
||||||
uint8_t isValid;
|
uint8_t isValid;
|
||||||
@@ -316,7 +316,7 @@ namespace cereal
|
|||||||
std::unique_ptr<ST> stPtr( new ST() );
|
std::unique_ptr<ST> stPtr( new ST() );
|
||||||
|
|
||||||
// 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( reinterpret_cast<T *>( stPtr.get() ) );
|
memory_detail::LoadAndConstructLoadWrapper<Archive, T> loadWrapper( reinterpret_cast<T *>( stPtr.get() ) );
|
||||||
|
|
||||||
// Initialize storage
|
// Initialize storage
|
||||||
ar( _CEREAL_NVP("data", loadWrapper) );
|
ar( _CEREAL_NVP("data", loadWrapper) );
|
||||||
@@ -328,10 +328,10 @@ namespace cereal
|
|||||||
ptr.reset( nullptr );
|
ptr.reset( nullptr );
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Loading std::unique_ptr, case when no load_and_allocate (wrapper implementation)
|
//! Loading std::unique_ptr, case when no load_and_construct (wrapper implementation)
|
||||||
/*! @internal */
|
/*! @internal */
|
||||||
template <class Archive, class T, class D> inline
|
template <class Archive, class T, class D> inline
|
||||||
typename std::enable_if<!traits::has_load_and_allocate<T, Archive>::value, void>::type
|
typename std::enable_if<!traits::has_load_and_construct<T, Archive>::value, void>::type
|
||||||
load( Archive & ar, memory_detail::PtrWrapper<std::unique_ptr<T, D> &> & wrapper )
|
load( Archive & ar, memory_detail::PtrWrapper<std::unique_ptr<T, D> &> & wrapper )
|
||||||
{
|
{
|
||||||
uint8_t isValid;
|
uint8_t isValid;
|
||||||
@@ -341,7 +341,7 @@ namespace cereal
|
|||||||
|
|
||||||
if( isValid )
|
if( isValid )
|
||||||
{
|
{
|
||||||
ptr.reset( detail::Load<T, Archive>::load_andor_allocate() );
|
ptr.reset( detail::Construct<T, Archive>::load_andor_construct() );
|
||||||
ar( *ptr );
|
ar( *ptr );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ namespace cereal
|
|||||||
@internal */
|
@internal */
|
||||||
template<class Archive, class T> inline
|
template<class Archive, class T> inline
|
||||||
typename std::enable_if<(std::is_default_constructible<T>::value
|
typename std::enable_if<(std::is_default_constructible<T>::value
|
||||||
|| traits::has_load_and_allocate<T, Archive>::value)
|
|| traits::has_load_and_construct<T, Archive>::value)
|
||||||
&& !std::is_abstract<T>::value, bool>::type
|
&& !std::is_abstract<T>::value, bool>::type
|
||||||
serialize_wrapper(Archive & ar, std::shared_ptr<T> & ptr, std::uint32_t const nameid)
|
serialize_wrapper(Archive & ar, std::shared_ptr<T> & ptr, std::uint32_t const nameid)
|
||||||
{
|
{
|
||||||
@@ -151,7 +151,7 @@ namespace cereal
|
|||||||
@internal */
|
@internal */
|
||||||
template<class Archive, class T, class D> inline
|
template<class Archive, class T, class D> inline
|
||||||
typename std::enable_if<(std::is_default_constructible<T>::value
|
typename std::enable_if<(std::is_default_constructible<T>::value
|
||||||
|| traits::has_load_and_allocate<T, Archive>::value)
|
|| traits::has_load_and_construct<T, Archive>::value)
|
||||||
&& !std::is_abstract<T>::value, bool>::type
|
&& !std::is_abstract<T>::value, bool>::type
|
||||||
serialize_wrapper(Archive & ar, std::unique_ptr<T, D> & ptr, std::uint32_t const nameid)
|
serialize_wrapper(Archive & ar, std::unique_ptr<T, D> & ptr, std::uint32_t const nameid)
|
||||||
{
|
{
|
||||||
@@ -171,12 +171,12 @@ namespace cereal
|
|||||||
@internal */
|
@internal */
|
||||||
template<class Archive, class T> inline
|
template<class Archive, class T> inline
|
||||||
typename std::enable_if<(!std::is_default_constructible<T>::value
|
typename std::enable_if<(!std::is_default_constructible<T>::value
|
||||||
&& !traits::has_load_and_allocate<T, Archive>::value)
|
&& !traits::has_load_and_construct<T, Archive>::value)
|
||||||
|| std::is_abstract<T>::value, bool>::type
|
|| std::is_abstract<T>::value, bool>::type
|
||||||
serialize_wrapper(Archive &, std::shared_ptr<T> &, std::uint32_t const nameid)
|
serialize_wrapper(Archive &, std::shared_ptr<T> &, std::uint32_t const nameid)
|
||||||
{
|
{
|
||||||
if(nameid & detail::msb2_32bit)
|
if(nameid & detail::msb2_32bit)
|
||||||
throw cereal::Exception("Cannot load a polymorphic type that is not default constructable and does not have a load_and_allocate function");
|
throw cereal::Exception("Cannot load a polymorphic type that is not default constructable and does not have a load_and_construct function");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,12 +188,12 @@ namespace cereal
|
|||||||
@internal */
|
@internal */
|
||||||
template<class Archive, class T, class D> inline
|
template<class Archive, class T, class D> inline
|
||||||
typename std::enable_if<(!std::is_default_constructible<T>::value
|
typename std::enable_if<(!std::is_default_constructible<T>::value
|
||||||
&& !traits::has_load_and_allocate<T, Archive>::value)
|
&& !traits::has_load_and_construct<T, Archive>::value)
|
||||||
|| std::is_abstract<T>::value, bool>::type
|
|| std::is_abstract<T>::value, bool>::type
|
||||||
serialize_wrapper(Archive &, std::unique_ptr<T, D> &, std::uint32_t const nameid)
|
serialize_wrapper(Archive &, std::unique_ptr<T, D> &, std::uint32_t const nameid)
|
||||||
{
|
{
|
||||||
if(nameid & detail::msb2_32bit)
|
if(nameid & detail::msb2_32bit)
|
||||||
throw cereal::Exception("Cannot load a polymorphic type that is not default constructable and does not have a load_and_allocate function");
|
throw cereal::Exception("Cannot load a polymorphic type that is not default constructable and does not have a load_and_construct function");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} // polymorphic_detail
|
} // polymorphic_detail
|
||||||
@@ -360,7 +360,7 @@ namespace cereal
|
|||||||
binding->second.unique_ptr(&ar, ptr.get());
|
binding->second.unique_ptr(&ar, ptr.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Loading std::unique_ptr, case when user provides load_and_allocate for polymorphic types
|
//! Loading std::unique_ptr, case when user provides load_and_construct for polymorphic types
|
||||||
template <class Archive, class T, class D> inline
|
template <class Archive, class T, class D> inline
|
||||||
typename std::enable_if<std::is_polymorphic<T>::value, void>::type
|
typename std::enable_if<std::is_polymorphic<T>::value, void>::type
|
||||||
load( Archive & ar, std::unique_ptr<T, D> & ptr )
|
load( Archive & ar, std::unique_ptr<T, D> & ptr )
|
||||||
|
|||||||
14
sandbox.cpp
14
sandbox.cpp
@@ -261,27 +261,27 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <class Archive>
|
template <class Archive>
|
||||||
static void load_and_allocate( Archive & ar, cereal::allocate<NoDefaultCtor> & allocate )
|
static void load_and_construct( Archive & ar, cereal::construct<NoDefaultCtor> & construct )
|
||||||
{
|
{
|
||||||
int y;
|
int y;
|
||||||
ar( y );
|
ar( y );
|
||||||
allocate( y );
|
construct( y );
|
||||||
allocate->z = 33;
|
construct->z = 33;
|
||||||
allocate.ptr()->z = 33;
|
construct.ptr()->z = 33;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//namespace cereal
|
//namespace cereal
|
||||||
//{
|
//{
|
||||||
// template <>
|
// template <>
|
||||||
// struct LoadAndAllocate<NoDefaultCtor>
|
// struct LoadAndConstruct<NoDefaultCtor>
|
||||||
// {
|
// {
|
||||||
// template <class Archive>
|
// template <class Archive>
|
||||||
// static void load_and_allocate( Archive & ar, cereal::allocate<NoDefaultCtor> & allocate )
|
// static void load_and_construct( Archive & ar, cereal::construct<NoDefaultCtor> & construct )
|
||||||
// {
|
// {
|
||||||
// int y;
|
// int y;
|
||||||
// ar( y );
|
// ar( y );
|
||||||
// allocate( y );
|
// construct( y );
|
||||||
// }
|
// }
|
||||||
// };
|
// };
|
||||||
//}
|
//}
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ struct Test
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <class Archive>
|
template <class Archive>
|
||||||
static Test * load_and_allocate( Archive & )
|
static Test * load_and_construct( Archive & )
|
||||||
{
|
{
|
||||||
return new Test();
|
return new Test();
|
||||||
}
|
}
|
||||||
@@ -84,12 +84,12 @@ void save( Archive &, Test const & )
|
|||||||
namespace cereal
|
namespace cereal
|
||||||
{
|
{
|
||||||
template <>
|
template <>
|
||||||
struct LoadAndAllocate<Test>
|
struct LoadAndConstruct<Test>
|
||||||
{
|
{
|
||||||
template <class Archive>
|
template <class Archive>
|
||||||
static void load_and_allocate( Archive &, cereal::allocate<Test> & allocate )
|
static void load_and_construct( Archive &, cereal::construct<Test> & construct )
|
||||||
{
|
{
|
||||||
allocate();
|
construct();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -130,10 +130,10 @@ int main()
|
|||||||
typedef Test T;
|
typedef Test T;
|
||||||
std::cout << std::boolalpha;
|
std::cout << std::boolalpha;
|
||||||
|
|
||||||
// Test Load and Allocate internal/external
|
// Test Load and Construct internal/external
|
||||||
std::cout << "\tload_and_allocate" << std::endl;
|
std::cout << "\tload_and_construct" << std::endl;
|
||||||
std::cout << cereal::traits::has_member_load_and_allocate<T, Archive>::value << std::endl;
|
std::cout << cereal::traits::has_member_load_and_construct<T, Archive>::value << std::endl;
|
||||||
std::cout << cereal::traits::has_non_member_load_and_allocate<T, Archive>::value << std::endl;
|
std::cout << cereal::traits::has_non_member_load_and_construct<T, Archive>::value << std::endl;
|
||||||
|
|
||||||
// serialize
|
// serialize
|
||||||
std::cout << "\tserialize" << std::endl;
|
std::cout << "\tserialize" << std::endl;
|
||||||
@@ -172,7 +172,7 @@ int main()
|
|||||||
|
|
||||||
// array size
|
// array size
|
||||||
std::cout << typeid(A).name() << std::endl;
|
std::cout << typeid(A).name() << std::endl;
|
||||||
std::cout << typeid(cereal::traits::has_load_and_allocate<int, bool>).name() << std::endl;
|
std::cout << typeid(cereal::traits::has_load_and_construct<int, bool>).name() << std::endl;
|
||||||
|
|
||||||
// extra testing
|
// extra testing
|
||||||
|
|
||||||
|
|||||||
@@ -1042,20 +1042,20 @@ std::ostream& operator<<(std::ostream& os, MemoryCycle const & s)
|
|||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
|
|
||||||
class MemoryCycleLoadAndAllocate
|
class MemoryCycleLoadAndConstruct
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MemoryCycleLoadAndAllocate( int v ) :
|
MemoryCycleLoadAndConstruct( int v ) :
|
||||||
value( v )
|
value( v )
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
MemoryCycleLoadAndAllocate( int v,
|
MemoryCycleLoadAndConstruct( int v,
|
||||||
std::weak_ptr<MemoryCycleLoadAndAllocate> p ) :
|
std::weak_ptr<MemoryCycleLoadAndConstruct> p ) :
|
||||||
value( v ),
|
value( v ),
|
||||||
ptr( p )
|
ptr( p )
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
bool operator==( MemoryCycleLoadAndAllocate const & other ) const
|
bool operator==( MemoryCycleLoadAndConstruct const & other ) const
|
||||||
{
|
{
|
||||||
return value == other.value && ptr.lock() == other.ptr.lock();
|
return value == other.value && ptr.lock() == other.ptr.lock();
|
||||||
}
|
}
|
||||||
@@ -1067,20 +1067,20 @@ class MemoryCycleLoadAndAllocate
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <class Archive>
|
template <class Archive>
|
||||||
static void load_and_allocate( Archive & ar, cereal::allocate<MemoryCycleLoadAndAllocate> & allocate )
|
static void load_and_construct( Archive & ar, cereal::construct<MemoryCycleLoadAndConstruct> & construct )
|
||||||
{
|
{
|
||||||
int value;
|
int value;
|
||||||
std::weak_ptr<MemoryCycleLoadAndAllocate> ptr;
|
std::weak_ptr<MemoryCycleLoadAndConstruct> ptr;
|
||||||
|
|
||||||
ar( value, ptr );
|
ar( value, ptr );
|
||||||
allocate( value, ptr );
|
construct( value, ptr );
|
||||||
}
|
}
|
||||||
|
|
||||||
int value;
|
int value;
|
||||||
std::weak_ptr<MemoryCycleLoadAndAllocate> ptr;
|
std::weak_ptr<MemoryCycleLoadAndConstruct> ptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& os, MemoryCycleLoadAndAllocate const & s)
|
std::ostream& operator<<(std::ostream& os, MemoryCycleLoadAndConstruct const & s)
|
||||||
{
|
{
|
||||||
os << "[value: " << s.value << " ptr: " << s.ptr.lock() << "]";
|
os << "[value: " << s.value << " ptr: " << s.ptr.lock() << "]";
|
||||||
return os;
|
return os;
|
||||||
@@ -1096,7 +1096,7 @@ void test_memory_cycles()
|
|||||||
{
|
{
|
||||||
auto o_ptr1 = std::make_shared<MemoryCycle>( random_value<int>(gen) );
|
auto o_ptr1 = std::make_shared<MemoryCycle>( random_value<int>(gen) );
|
||||||
o_ptr1->ptr = o_ptr1;
|
o_ptr1->ptr = o_ptr1;
|
||||||
auto o_ptr2 = std::make_shared<MemoryCycleLoadAndAllocate>( random_value<int>(gen) );
|
auto o_ptr2 = std::make_shared<MemoryCycleLoadAndConstruct>( random_value<int>(gen) );
|
||||||
o_ptr2->ptr = o_ptr2;
|
o_ptr2->ptr = o_ptr2;
|
||||||
|
|
||||||
std::ostringstream os;
|
std::ostringstream os;
|
||||||
@@ -1157,11 +1157,11 @@ struct OneLA
|
|||||||
{ ar( x ); }
|
{ ar( x ); }
|
||||||
|
|
||||||
template <class Archive>
|
template <class Archive>
|
||||||
static void load_and_allocate( Archive & ar, cereal::allocate<OneLA> & allocate )
|
static void load_and_construct( Archive & ar, cereal::construct<OneLA> & construct )
|
||||||
{
|
{
|
||||||
int xx;
|
int xx;
|
||||||
ar( xx );
|
ar( xx );
|
||||||
allocate( xx );
|
construct( xx );
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==( OneLA const & other ) const
|
bool operator==( OneLA const & other ) const
|
||||||
@@ -1197,14 +1197,14 @@ std::ostream& operator<<(std::ostream& os, TwoLA const & s)
|
|||||||
namespace cereal
|
namespace cereal
|
||||||
{
|
{
|
||||||
template <>
|
template <>
|
||||||
struct LoadAndAllocate<TwoLA>
|
struct LoadAndConstruct<TwoLA>
|
||||||
{
|
{
|
||||||
template <class Archive>
|
template <class Archive>
|
||||||
static void load_and_allocate( Archive & ar, cereal::allocate<TwoLA> & allocate )
|
static void load_and_construct( Archive & ar, cereal::construct<TwoLA> & construct )
|
||||||
{
|
{
|
||||||
int xx;
|
int xx;
|
||||||
ar( xx );
|
ar( xx );
|
||||||
allocate( xx );
|
construct( xx );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -1223,11 +1223,11 @@ struct ThreeLA : std::enable_shared_from_this<ThreeLA>
|
|||||||
{ return x == other.x; }
|
{ return x == other.x; }
|
||||||
|
|
||||||
template <class Archive>
|
template <class Archive>
|
||||||
static void load_and_allocate( Archive & ar, cereal::allocate<ThreeLA> & allocate )
|
static void load_and_construct( Archive & ar, cereal::construct<ThreeLA> & construct )
|
||||||
{
|
{
|
||||||
int xx;
|
int xx;
|
||||||
ar( xx );
|
ar( xx );
|
||||||
allocate( xx );
|
construct( xx );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1238,7 +1238,7 @@ std::ostream& operator<<(std::ostream& os, ThreeLA const & s)
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <class IArchive, class OArchive>
|
template <class IArchive, class OArchive>
|
||||||
void test_memory_load_allocate()
|
void test_memory_load_construct()
|
||||||
{
|
{
|
||||||
std::random_device rd;
|
std::random_device rd;
|
||||||
std::mt19937 gen(rd());
|
std::mt19937 gen(rd());
|
||||||
@@ -1290,24 +1290,24 @@ void test_memory_load_allocate()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE( binary_memory_load_allocate )
|
BOOST_AUTO_TEST_CASE( binary_memory_load_construct )
|
||||||
{
|
{
|
||||||
test_memory_load_allocate<cereal::BinaryInputArchive, cereal::BinaryOutputArchive>();
|
test_memory_load_construct<cereal::BinaryInputArchive, cereal::BinaryOutputArchive>();
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE( portable_binary_memory_load_allocate )
|
BOOST_AUTO_TEST_CASE( portable_binary_memory_load_construct )
|
||||||
{
|
{
|
||||||
test_memory_load_allocate<cereal::PortableBinaryInputArchive, cereal::PortableBinaryOutputArchive>();
|
test_memory_load_construct<cereal::PortableBinaryInputArchive, cereal::PortableBinaryOutputArchive>();
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE( xml_memory_load_allocate )
|
BOOST_AUTO_TEST_CASE( xml_memory_load_construct )
|
||||||
{
|
{
|
||||||
test_memory_load_allocate<cereal::XMLInputArchive, cereal::XMLOutputArchive>();
|
test_memory_load_construct<cereal::XMLInputArchive, cereal::XMLOutputArchive>();
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE( json_memory_load_allocate )
|
BOOST_AUTO_TEST_CASE( json_memory_load_construct )
|
||||||
{
|
{
|
||||||
test_memory_load_allocate<cereal::JSONInputArchive, cereal::JSONOutputArchive>();
|
test_memory_load_construct<cereal::JSONInputArchive, cereal::JSONOutputArchive>();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ######################################################################
|
// ######################################################################
|
||||||
@@ -3152,11 +3152,11 @@ struct PolyDerivedLA : public PolyLA
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <class Archive>
|
template <class Archive>
|
||||||
static void load_and_allocate( Archive & ar, cereal::allocate<PolyDerivedLA> & allocate )
|
static void load_and_construct( Archive & ar, cereal::construct<PolyDerivedLA> & construct )
|
||||||
{
|
{
|
||||||
int xx;
|
int xx;
|
||||||
ar( xx );
|
ar( xx );
|
||||||
allocate( xx );
|
construct( xx );
|
||||||
}
|
}
|
||||||
|
|
||||||
void foo() {}
|
void foo() {}
|
||||||
|
|||||||
Reference in New Issue
Block a user