Make action classes non-relocatable

This fixes an issue with auto_ptr. As shown by missing coverage the
actual copy/move ctors are not required as C++11 emplace functions can
be used.
Furthermore some places using shared_ptr could be replaced by unique_ptr
leading to better performance.
This commit is contained in:
Alexander Grund 2020-07-14 21:17:14 +02:00
parent f3d6564d2b
commit d9f9fce6fc
No known key found for this signature in database
GPG key ID: AA48A0760367A42B
5 changed files with 54 additions and 55 deletions

View file

@ -25,7 +25,16 @@ namespace detail
typedef std::function< Signature > functor_type; typedef std::function< Signature > functor_type;
typedef std::function< Result() > action_type; typedef std::function< Result() > action_type;
protected:
// Meant to be subclassed and not be directly used
// Non-relocatable (contained functions may wrap references/pointers which could be invalidated)
action_base() = default;
action_base(const action_base&) = delete;
action_base(action_base&&) = delete;
action_base& operator=(const action_base&) = delete;
action_base& operator=(action_base&&) = delete;
public: public:
const functor_type& functor() const const functor_type& functor() const
{ {
return f_; return f_;
@ -91,11 +100,6 @@ namespace detail
} }
private: private:
template< typename Value >
static Value&& move( Value& t )
{
return std::move( t );
}
struct value struct value
{ {
value() = default; value() = default;
@ -106,41 +110,28 @@ namespace detail
template< typename T > template< typename T >
struct value_imp : value struct value_imp : value
{ {
typedef std::remove_const_t<std::remove_reference_t<T>> value_type; typedef std::remove_const_t<std::remove_reference_t<T>> type;
value_imp( value_type&& t ) template< typename U >
: t_( std::move( t ) ) value_imp( U&& t ) : t_( std::forward<U>( t ) )
{} {}
value_imp( const value_type& t ) type t_;
: t_( t )
{}
template< typename Y >
value_imp( Y* y )
: t_( y )
{}
value_type t_;
}; };
template< typename T > template< typename T >
T& store( T&& t ) typename value_imp<T>::type& store( T&& t )
{ {
v_ = std::make_shared< value_imp<T> >( std::move( t ) ); v_ = std::make_unique< value_imp<T> >( std::forward<T>( t ) );
return static_cast< value_imp< T >& >( *v_ ).t_;
}
template< typename T >
T& store( const T& t )
{
v_ = std::make_shared< value_imp<T> >( t );
return static_cast< value_imp< T >& >( *v_ ).t_; return static_cast< value_imp< T >& >( *v_ ).t_;
} }
template< typename T > template< typename T >
std::remove_reference_t< Result >& store( T* t ) std::remove_reference_t< Result >& store( T* t )
{ {
v_ = std::make_shared< value_imp<Result> >( t ); v_ = std::make_unique< value_imp<Result> >( t );
return static_cast< value_imp< Result >& >( *v_ ).t_; return static_cast< value_imp< Result >& >( *v_ ).t_;
} }
std::shared_ptr< value > v_; std::unique_ptr< value > v_;
}; };
template< typename Signature > template< typename Signature >
@ -159,14 +150,6 @@ namespace detail
: public action_base< std::auto_ptr< Result >, Signature > : public action_base< std::auto_ptr< Result >, Signature >
{ {
public: public:
action() = default;
action( const action& rhs )
: v_( rhs.v_.release() )
{
if( v_.get() )
returns( std::ref( v_ ) );
}
template< typename Y > template< typename Y >
void returns( Y* r ) void returns( Y* r )
{ {

View file

@ -133,9 +133,9 @@ namespace detail
{ {
public: public:
expectation() expectation()
: invocation_( std::make_shared< unlimited >() ) : invocation_( std::make_unique< unlimited >() )
, matcher_( , matcher_(
std::make_shared< std::make_unique<
default_matcher< default_matcher<
void( BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T) ) void( BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T) )
> >
@ -144,9 +144,9 @@ namespace detail
, line_( 0 ) , line_( 0 )
{} {}
expectation( const char* file, int line ) expectation( const char* file, int line )
: invocation_( std::make_shared< unlimited >() ) : invocation_( std::make_unique< unlimited >() )
, matcher_( , matcher_(
std::make_shared< std::make_unique<
default_matcher< default_matcher<
void( BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T) ) void( BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T) )
> >
@ -166,9 +166,9 @@ namespace detail
sequence->remove( this ); sequence->remove( this );
} }
void invoke( const std::shared_ptr< invocation >& i ) void invoke( std::unique_ptr< invocation > i )
{ {
invocation_ = i; invocation_ = std::move(i);
} }
#ifndef MOCK_NUM_ARGS_0 #ifndef MOCK_NUM_ARGS_0
@ -178,7 +178,7 @@ namespace detail
expectation& with( expectation& with(
BOOST_PP_ENUM_BINARY_PARAMS(MOCK_NUM_ARGS, Constraint_, c) ) BOOST_PP_ENUM_BINARY_PARAMS(MOCK_NUM_ARGS, Constraint_, c) )
{ {
matcher_ = std::make_shared< matcher_ = std::make_unique<
single_matcher< single_matcher<
void( BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, Constraint_) ), void( BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, Constraint_) ),
void( BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T) ) void( BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T) )
@ -189,7 +189,7 @@ namespace detail
template< typename Constraint > template< typename Constraint >
expectation& with( const Constraint& c ) expectation& with( const Constraint& c )
{ {
matcher_ = std::make_shared< matcher_ = std::make_unique<
multi_matcher< multi_matcher<
Constraint, Constraint,
void( BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T) ) void( BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T) )
@ -250,8 +250,8 @@ namespace detail
} }
private: private:
std::shared_ptr< invocation > invocation_; std::unique_ptr< invocation > invocation_;
std::shared_ptr< std::unique_ptr<
matcher_base< matcher_base<
void( BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T) ) void( BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T) )
> >

View file

@ -125,32 +125,32 @@ namespace detail
} }
wrapper& once() wrapper& once()
{ {
this->e_->invoke( std::make_shared< detail::once >() ); this->e_->invoke( std::make_unique< detail::once >() );
return *this; return *this;
} }
wrapper& never() wrapper& never()
{ {
this->e_->invoke( std::make_shared< detail::never >() ); this->e_->invoke( std::make_unique< detail::never >() );
return *this; return *this;
} }
wrapper& exactly( std::size_t count ) wrapper& exactly( std::size_t count )
{ {
this->e_->invoke( std::make_shared< detail::exactly >( count ) ); this->e_->invoke( std::make_unique< detail::exactly >( count ) );
return *this; return *this;
} }
wrapper& at_least( std::size_t min ) wrapper& at_least( std::size_t min )
{ {
this->e_->invoke( std::make_shared< detail::at_least >( min ) ); this->e_->invoke( std::make_unique< detail::at_least >( min ) );
return *this; return *this;
} }
wrapper& at_most( std::size_t max ) wrapper& at_most( std::size_t max )
{ {
this->e_->invoke( std::make_shared< detail::at_most >( max ) ); this->e_->invoke( std::make_unique< detail::at_most >( max ) );
return *this; return *this;
} }
wrapper& between( std::size_t min, std::size_t max ) wrapper& between( std::size_t min, std::size_t max )
{ {
this->e_->invoke( std::make_shared< detail::between >( min, max ) ); this->e_->invoke( std::make_unique< detail::between >( min, max ) );
return *this; return *this;
} }
@ -217,14 +217,14 @@ namespace detail
wrapper expect( const char* file, int line ) wrapper expect( const char* file, int line )
{ {
lock _( mutex_ ); lock _( mutex_ );
expectations_.push_back( expectation_type( file, line ) ); expectations_.emplace_back( file, line );
valid_ = true; valid_ = true;
return wrapper( mutex_, expectations_.back() ); return wrapper( mutex_, expectations_.back() );
} }
wrapper expect() wrapper expect()
{ {
lock _( mutex_ ); lock _( mutex_ );
expectations_.push_back( expectation_type() ); expectations_.emplace_back( );
valid_ = true; valid_ = true;
return wrapper( mutex_, expectations_.back() ); return wrapper( mutex_, expectations_.back() );
} }

View file

@ -45,9 +45,12 @@ namespace detail
const char* name = info.name(); const char* name = info.name();
#ifdef __GNUC__ #ifdef __GNUC__
int status = 0; int status = 0;
std::shared_ptr< char > demangled( struct Deleter
abi::__cxa_demangle( name, 0, 0, &status ), {
&std::free ); void operator()(const void* p) { std::free(const_cast<void*>(p)); }
};
std::unique_ptr< const char, Deleter > demangled(
abi::__cxa_demangle( name, 0, 0, &status ));
if( ! status && demangled ) if( ! status && demangled )
serialize( s, demangled.get() ); serialize( s, demangled.get() );
else else

View file

@ -535,6 +535,19 @@ BOOST_FIXTURE_TEST_CASE( triggering_an_expectation_returns_the_set_auto_ptr_valu
BOOST_CHECK( ! f().get() ); BOOST_CHECK( ! f().get() );
CHECK_CALLS( 2 ); CHECK_CALLS( 2 );
} }
{
mock::detail::function< std::auto_ptr< int >() > f;
f.expect().once().returns( new int( 1 ) );
f.expect().once().returns( new int( 2 ) );
f.expect().once().returns( new int( 3 ) );
f.expect().returns( new int( 4 ) );
BOOST_CHECK_EQUAL( 1, *f() );
BOOST_CHECK_EQUAL( 2, *f() );
BOOST_CHECK_EQUAL( 3, *f() );
BOOST_CHECK_EQUAL( 4, *f() );
BOOST_CHECK( ! f().get() );
CHECK_CALLS( 5 );
}
{ {
mock::detail::function< std::auto_ptr< int >() > f; mock::detail::function< std::auto_ptr< int >() > f;
f.expect().returns( std::auto_ptr< int >( new int( 3 ) ) ); f.expect().returns( std::auto_ptr< int >( new int( 3 ) ) );