Applying C++11 move semantics to bound functions - c++

I have some existing C++98 code that makes use of boost::function and boost:bind for asynchronous callbacks. Some relevant simplified fragments of the code include:
typedef boost::function<void (boost::system::error_code, size_t)> WriteHandler;
struct WriteOperation
{
WriteOperation(const boost::shared_ptr<IDevice>& device,
const std::string& data, const WriteHandler& handler)
: m_Device(device), m_Data(data), m_Handler(handler) {}
private:
boost::shared_ptr<IDevice> m_Device;
std::string m_Data;
WriteHandler m_Handler;
void Complete()
{
boost::system::error_code ec;
size_t len;
...
Async::Post(boost::bind(m_Handler, ec, len));
}
};
struct Device : public IDevice
{
void Write(const std::string& data, const WriteHandler& callback)
{
...
Async::Start(new WriteOperation(shared_from_this(), data,
boost::bind(&Device::HandleWrite, this, handler, _1, _2)));
}
private:
void HandleWrite(const WriteHandler& callback,
boost::system::error_code ec, size_t len)
{
...
callback(ec, len);
}
};
There is one required copy, when constructing the WriteOperation, but other than that I'm trying to avoid copies since they can be quite expensive.
I'm pondering how this should best be written in the C++11 world. The obvious low-hanging fruit is that the WriteOperation constructor internally copies its arguments to its fields, so should use the automatic copying idiom:
WriteOperation(boost::shared_ptr<IDevice> device,
std::string data, WriteHandler handler)
: m_Device(std::move(device)), m_Data(std::move(data)), m_Handler(std::move(handler))
{}
(And of course the bare new should be replaced with unique_ptr, but that's a side issue.)
However I don't think this actually gains anything given the current implementation of Device::Write, so that ought to change too. My problem is that I don't really see a good way to do it. According to this advice, I have three options:
Declare multiple overloads (one with const& and one with &&) -- but since this has two parameters, both of which could benefit from move semantics, this would require four overloads -- getting exponentially worse for methods with more parameters. Additionally this leads to either code duplication or scattering the code over additional methods, which can impair readability.
Pass by value and move (similar to the WriteOperation constructor). This is perhaps the cleanest option when the body always makes a copy, which is true if the WriteOperation constructor is actually called, but what if the elided section contains logic that might return without constructing a WriteOperation? There's a wasted copy in this case.
Template and perfect forward. This requires an ugly SFINAE hack that confuses Intellisense and impairs readability (or worse, leaving the parameter type unconstrained), and requires that the implementation be put into the header, which is sometimes undesirable. And it interferes with type conversions, eg. a SFINAE enable_if is_same looking for std::string will not accept a const char * literal, while the original const& version will.
Am I missing something? Is there a better solution? Or is this just a case where move semantics don't make any difference?
A related case:
typedef boost::function<void (boost::system::error_code, const std::string&)> ReadHandler;
void Read(const ReadHandler& callback)
{
... boost::bind(&Device::HandleRead, this, callback, _1, _2) ...
}
void HandleRead(const ReadHandler& callback,
boost::system::error_code ec, const std::string& data)
{
...
callback(ec, data);
}
This all seems like it should be ok, with no copying and no need for move semantics. And yet again I'm unsure about the ReadHandler passed to Read.

In rough order:
If copy is just as expensive as move, take it by const&.
If you reliably keep a copy, and move is cheap, take by value.
Failing that, you can stuff it in a header and are ok with sfinae or unconstrained templates, use forwarding references.
Failing that, if there are a limited number of arguments, write each overload. This is 2^n in the number of parameters, so there better not be too many. Forward internally to a forwarding reference based implementation.
Failing that, do you really need efficiency here?
Failing that, type erase to "creator of T".
template<class T, using Base=std::function<T()>>
struct creator_of: Base
{
template<class U,
std::enable_if_t<std::is_constructible<T, U&&>{},int> =0
>
creator_of(U&&u):
Base([&]()->T{ return std::forward<U>(u); })
{}
template<class U,
std::enable_if_t<std::is_constructible<T, std::result_of_t<std::decay_t<U>()>{},int> =0
>
creator_of(U&&u):
Base(std::forward<U>(u))
{}
creator_of(creator_of&&)=default;
creator_of():
Base([]()->T{return {};}}
{}
};
augment as needed. A creator_of<std::string> can be constructed from things that can construct a std::string, or from a function object returning a std::string.
Internally you can call () once on it.
(Code not compiled, but design is sound.)

To avoid the combinatorial explosion, while supporting the case where it turns out inside the called function that no argument copies are needed, you can defer the copying.
That's effectively a lazy evaluation scheme, but for this special case only.
With a support class like the one below one needs to be keenly aware that an instance might just hold a pointer to a short-lived caller's object. I.e., don't move a Lazy_copy_ into storage that outlives the call.
#include <iostream>
#include <new>
#include <string> // std::string
#include <utility> // std::move, std::forward
using namespace std;
//------------------------------------ Machinery:
#ifdef TRACE
inline void trace( string const& s )
{
clog << ": " << s << endl;
}
#else
inline void trace( string const& ) {}
#endif
struct Emplace {};
template< class Item >
class Lazy_copy_
{
private:
Item const* p_callers_item_;
union{ Item item_copy_; }; // Left uninitialized if p_callers_item_.
void ensure_is_copy()
{
if( p_callers_item_ )
{
::new( &item_copy_ ) Item( *p_callers_item_ );
trace( "ensure_is_copy: made copy" );
p_callers_item_ = nullptr;
}
}
public:
auto item() const
-> Item const&
{ return (p_callers_item_? *p_callers_item_ : item_copy_); }
auto item_copy()
-> Item&
{
ensure_is_copy();
return item_copy_;
}
~Lazy_copy_()
{
if( not p_callers_item_ ) { item_copy_.Item::~Item(); }
}
Lazy_copy_( Lazy_copy_ const& other )
: p_callers_item_( other.p_callers_item_ )
{
if( p_callers_item_ )
{
ensure_is_copy();
}
else
{
::new( &item_copy_ ) Item( other.item_copy_ );
trace( "<init>( Lazy_copy ): made copy" );
}
}
Lazy_copy_( Lazy_copy_&& other )
: p_callers_item_( other.p_callers_item_ )
{
if( not p_callers_item_ )
{
::new( &item_copy_ ) Item( move( other.item_copy_ ) );
trace( "<init>( Lazy_copy&& ): moved" );
}
}
Lazy_copy_( Item const& item )
: p_callers_item_( &item )
{}
Lazy_copy_( Item&& temp_item )
: p_callers_item_( nullptr )
, item_copy_( move( temp_item ) )
{
trace( "<init>( Item&& ): moved" );
}
template< class... Args >
Lazy_copy_( Emplace, Args&&... args )
: p_callers_item_( nullptr )
, item_copy_( forward<Args>( args )... )
{
trace( "<init>( Emplace, Args... ): Created item from constructor args" );
}
};
//------------------------------------ Example usage:
struct Thingy
{
string a, b, c;
void foo(
Lazy_copy_<string> arg_one,
Lazy_copy_<string> arg_two,
Lazy_copy_<string> arg_three
)
{
if( arg_one.item() == "no_copy" )
{
return; // The case of no copying needed.
}
a = move( arg_one.item_copy() );
b = move( arg_two.item_copy() );
c = move( arg_three.item_copy() );
}
};
auto main()
-> int
{
Thingy x;
string a = "A", b = "B", c = "C";
trace( "Call with copying:" );
x.foo( string( "a" ), b, c );
trace( "" );
trace( "Call without copying: " );
x.foo( string( "no_copy" ), b, c );
}
Output when built with TRACE defined:
: Call with copying:
: <init>( Item&& ): moved
: ensure_is_copy: made copy
: ensure_is_copy: made copy
:
: Call without copying:
: <init>( Item&& ): moved

Related

Interface with functions that take any type

I would like to define an interface for a message pump that is able to send and receive messages with a type specified by the user, to communicate e.g. between a producer and consumer.
Currently I have done it like that:
template <typename Message>
struct message_pump
{
virtual void send(Message &&) = 0;
//! Blocks if no message is available.
virtual Message receive() = 0;
};
Then I would like to use this message_pump interface as a member of an active class (the pattern from Herb Sutters' - "Prefer Using Active Objects Instead of Naked Threads"):
template <typename Message>
class active
{
private:
struct quit_message{};
using MessageProxy = typename std::variant<Message, quit_message>;
std::unique_ptr<message_pump<MessageProxy>> message_pump_impl;
std::function<void(Message&&)> message_handler;
std::thread worker_thread;
void thread_code() {
while(true)
{
auto m{message_pump_impl->receive()};
if(std::holds_alternative<quit_message>(m))
break;
message_handler(std::move(std::get<Message>(m)));
}
}
public:
active(std::unique_ptr<message_pump<MessageProxy>> message_pump_impl,
std::function<void(Message&&)> message_handler) :
message_pump_impl{std::move(message_pump_impl)},
message_handler{message_handler},
worker_thread{[this](){ this->thread_code(); }} {}
};
The problem here is that static and dynamic polymorphism doesn't mix well and it's not possible to inject the implementation of the message_pump without knowing the type of the underlying Message.
The reason I'm doing this active class is that that I would like to reuse it across various RTOSes, which provide different queue and thread class implementations, and still be able to test it on the local computer. (I've put in this listing std::thread just for simplification, because how to make the thread implementation injectable is a different topic).
The question is what's the preferred way - the most OOP and "as it should be done" way - to define the interface message_pump, to be able to easily inject the implementation to the active class?
I have a few solutions in mind:
Define struct message {} inside message_pump and make MessageProxy a struct which inherits from the message_pump::message. Then return std::unique_ptr<message> from the receive() interface function.
Use std::any instead of Message inside MessagePump.
Use static polymorphism and inject message_pump implementation through a template parameter. Then the message_pump interface is not needed to be defined explicitly and we will get compiler errors if the implementer doesn't have a specific function.
Use C++20 concepts? (I would like also to know how to solve it with C++17).
Mix Ad.4 and Ad.5: use template parameter but explicitly define what interface it shall implement.
Other?
Use dynamic polymorphism. This works, however, it requires the active type to expose what type it uses internally to hold the messages so that the right type of queue can be constructed.
Define struct message {} inside message_pump and make MessageProxy a struct which inherits from the message_pump::message. This doesn't gain us anything if we are using dynamic polymorphism. However, if using static polymorphism user messages can derive from active::message which can derive from message_pump::message, which makes it possible to add non-movable messages without "emplace" methods. Having to derive messages from active::message is a down-side that shouldn't be overlooked especially if a message could reuse an existing type such as int otherwise. This will also require the messages to be dynamically allocated even for queues that wouldn't normally require this.
Use std::any instead of Message inside MessagePump. If using dynamic polymorphism, it fixes the problem with active having to expose what type of messages it uses internally and allows active to not be a template. But losses static type checking and has runtime overhead. I wouldn't recommend this as static type checking can make refactoring a lot less error prone.
Use static polymorphism and inject message_pump implementation through a template parameter. If message_pump is a template template parameter, active won't have to expose what type of messages it uses internally. This is similar to the approach taken by the standard library. However, the error messages can be hard to understand.
Use C++20 concepts? (I would like also to know how to solve it with C++17). concepts can help document what methods a message_pump would need and might give better errors. I wouldn't try anything like this with c++17, as the c++17 versions tend to be hard to read and give little benefit in this case.
use template parameter but explicitly define what interface it shall implement. Basically what concepts are meant to achieve.
Other? implement a queue that works on multiple platforms perhaps using #ifdef and have active use that queue or default active's message_pump template parameter to that queue.
OK, you can use type erasure and opaque pointers in order to hide the details about both the message pump and message.
struct Message { std::string payload{ "Hello" }; };
struct VTable
{
void* ( *Receive )( void* ptr );
void ( *Send )( void* ptr, void* message );
void ( *Destroy_ )( void* ptr );
void* ( *Clone_ )( void* ptr );
void* ( *MoveClone_ )( void* ptr );
};
template<typename T>
constexpr VTable VTableFor
{
[ ]( void* ptr ) -> void* { return static_cast<T*>( ptr )->Receive( ); },
[ ]( void* ptr, void* message ) { static_cast<T*>( ptr )->Send( message ); },
[ ]( void* ptr ) { delete static_cast<T*>( ptr ); },
[ ]( void* ptr ) -> void* { return new T{ *static_cast<T*>( ptr ) }; },
[ ]( void* ptr ) -> void* { return new T{ std::move( *static_cast<T*>( ptr ) ) }; }
};
struct MessagePump
{
void* concrete_;
const VTable* vtable_;
template<typename T>
MessagePump( T&& t )
: concrete_( new T{ std::forward<T>( t ) } ),
vtable_{ &VTableFor<T> } { }
MessagePump( const MessagePump& rhs ) noexcept
: concrete_{ rhs.vtable_->Clone_( rhs.concrete_ ) },
vtable_{ rhs.vtable_ } { }
MessagePump( MessagePump&& rhs ) noexcept
: concrete_{ rhs.vtable_->MoveClone_( rhs.concrete_ ) },
vtable_{ rhs.vtable_ } { }
MessagePump& operator=( MessagePump rhs ) noexcept
{
swap( *this, rhs );
return *this;
}
friend void swap( MessagePump& lhs, MessagePump& rhs ) noexcept
{
using std::swap;
swap( lhs.concrete_, rhs.concrete_ );
swap( lhs.vtable_, rhs.vtable_ );
}
void* Receive( ) { return vtable_->Receive( concrete_ ); }
void Send( void* message ) { vtable_->Send( concrete_, message ); }
~MessagePump( ) { vtable_->Destroy_( concrete_ ); }
};
struct CustomPump
{
void* Receive( )
{ return new Message{ }; };
void Send( void* message )
{
auto ptr{ static_cast<Message*>( message ) };
std::cout << "Sending: " << ptr->payload << '\n';
delete ptr;
}
};
template<typename MessageType>
class Active
{
public:
using Callback = void( * )( MessageType* msg );
Active( MessagePump pump, Callback cb )
: pump_{ std::move( pump ) },
cb_{ cb } { }
void Start( )
{
while ( true )
{
auto message{ pump_.Receive( ) };
if ( !message )
{
std::cout << "No message\n";
break;
}
else
{
auto message{ static_cast<MessageType*>( result ) };
std::invoke( cb_, message );
pump_.Send( message );
}
}
}
private:
MessagePump pump_;
Callback cb_;
};
int main ( )
{
Active<Message> active{ CustomPump{ },
[ ]( Message* msg ){ std::cout << "Received: " << msg->payload << '\n'; } };
active.Start( );
}

C++03 smart pointer with free()

I have a char pointer that I need to transfer ownership of, and I would rather not have to handle its lifecycle myself if possible. The memory is allocated using malloc (no choice here).
As such I'm looking for something like C++11's unique_ptr, which manages ownership and allows a custom Deleter to be provided.
As the title suggests, I don't have access to C++11 features though. auto_ptr isn't a goer as far as I'm aware, as it calls delete rather than free.
Is there an appropriate smart pointer in this case, or will I have to manage the freeing of the memory myself?
As an alternative to writing it yourself you can introduce a dependency on Boost and just use boost::shared_ptr.
But for comparison, here’s minimal off-the-cuff C++11 and later code for an malloc/free based ownership transfer pointer, like std::unique:
template< class Type >
class My_ptr
{
private:
Type* p_;
My_ptr( My_ptr const& ) = delete;
operator=( My_ptr const& ) -> My_ptr& = delete;
public:
auto operator->() const
-> Type*
{ return p; }
auto operator*() const
-> Type&
{ return *p; }
~My_ptr() { free( p_ ); }
My_ptr( Type* p )
: p_( p )
{}
My_ptr( My_ptr&& other )
: p_( other.p_ )
{ other.p_ = nullptr; }
};
As you can see it's not much code in C++11.
Disclaimer: the above code has not been seen by compiler.
In C++03 the main problem is how to make it possible to return the smart pointer from a function, without allowing general copy construction, which would wreak havoc.
The solution used by std::auto_ptr was to involve a mediator pointer carrier class with implicit conversions. This was complex. I remember encountering a great number of idiosyncrasies in Visual C++'s implementation of std::auto_ptr, when I wrote a (once referenced by Wikipedia) pointer tutorial.
The code below, hopefully valid C++03 (tested with g++ -std=c++03), is instead based on the programmer explicitly indicating where a move operation is desired, by calling the as_movable member function. It uses volatile as a kind of tag, to ensure that only the moving constructor can fit when the result of as_movable is used as a constructor argument. The idea of using volatile as a tag in C++03, though in a quite different context, was once introdued by Andrei Alexandrescu; possibly by others before him, but as far as I recall his usage was where I first encountered that idea.
The placement allocation and deallocation operators, operator new and operator delete, are defined for exception safety. In particular, the placement operator delete defined here is only called implicitly, by a new-expression, when the relevant type's constructor indicates failure by throwing an exception. Then the memory is deallocated, using this operator, before the exception is re-thrown.
#include <exception> // std::terminate
#include <new> // std::bad_alloc
#include <stddef.h> // size_t
#include <stdlib.h> // malloc, free, NULL
#define MY_NEW( type, args ) \
::new type args
#define MY_MALLOC( type, args ) \
::new( my::c_memory_management ) type args
namespace my {
struct C_memory_management {};
C_memory_management const c_memory_management = C_memory_management();
} // namespace my
void*
operator new( size_t const size, my::C_memory_management )
{
void* result = malloc( size );
if( not result ) { throw std::bad_alloc(); }
return result;
}
// This operator is (only) called automatically by a new-expression where the
// constructor for the type, throws. After the call the exception is re-thrown.
void operator delete( void* const p, my::C_memory_management )
{
free( p );
}
#ifdef SUPPORT_ARRAYS
void*
operator new[]( size_t const size, my::C_memory_management const cmm )
{
return operator new( size, cmm );
}
void operator delete[]( void* const p, my::C_memory_management const cmm )
{
operator delete( p, cmm );
}
#endif
namespace my {
template< class Referent >
struct Destruction_via_delete_
{
static void destroy( Referent const* p )
{
try
{
delete p;
}
catch( ... )
{
std::terminate();
}
}
};
template< class Referent >
struct Destruction_via_free_
{
static void destroy( Referent const* p )
{
try
{
p->~Referent();
}
catch( ... )
{
std::terminate();
}
::free( const_cast<Referent*>( p ) );
}
};
template< class Referent >
class Auto_ptr_
{
public:
typedef void Destruction_func( Referent const* );
private:
Auto_ptr_& operator=( Auto_ptr_ const& ); // No copy assignment.
Auto_ptr_( Auto_ptr_ const& ); // No COPYING via copy constructor.
// A non-const argument copy constructor, for moving, is defined below.
Referent* p_;
Destruction_func* destroy_func_;
static void dummy_destroy_func( Referent const* ) {}
public:
Auto_ptr_ volatile&
as_movable()
{ return const_cast<Auto_ptr_ volatile&>( *this ); }
Referent*
release()
{
Referent* result = p_;
p_ = NULL;
return p_;
}
Referent*
operator->() const
{ return p_; }
Referent&
operator*() const
{ return *p_; }
~Auto_ptr_()
{ destroy_func_( p_ ); }
Auto_ptr_()
: p_( NULL )
, destroy_func_( &dummy_destroy_func )
{}
explicit Auto_ptr_(
Referent* const p,
Destruction_func* const destroy_func = &Destruction_via_delete_<Referent>::destroy
)
: p_( p )
, destroy_func_( destroy_func )
{}
explicit Auto_ptr_(
C_memory_management, // tag
Referent* const p
)
: p_( p )
, destroy_func_( &Destruction_via_free_<Referent>::destroy )
{}
// A C++03 emulation of move constructor; allows return of lvalue.
Auto_ptr_( Auto_ptr_ volatile& other )
: p_( other.p_ )
, destroy_func_( other.destroy_func_ )
{
other.p_ = NULL;
other.destroy_func_ = &dummy_destroy_func;
}
};
} // namespace my
#include <stdio.h>
struct Blah
{
char const* hello() const { return "Hello from Blah-land! :)"; }
~Blah() { printf( "<destroy>\n" ); }
Blah() { printf( "<init>\n" ); }
};
my::Auto_ptr_< Blah >
foo()
{
using namespace my;
Auto_ptr_< Blah > p( c_memory_management, MY_MALLOC( Blah,() ) );
return p.as_movable();
}
void bar( my::Auto_ptr_<Blah> const p )
{
printf( "%s\n", p->hello() );
}
int main()
{
my::Auto_ptr_<Blah> p = foo().as_movable();
printf( "Calling bar()...\n" );
bar( p.as_movable() );
printf( "Returned from bar().\n" );
}
Output:
<init>
Calling bar()...
Hello from Blah-land! :)
<destroy>
Returned from bar().
Disclaimer: I've not written any unit test for the above code, indeed the only testing is what's shown above, that that works. Testing the various cases that one wants this to work for is IMHO necessary for use of this in a production code.

const auto && really not useful?

Here
https://youtu.be/dTeKf5Oek2c?t=2939
Stephen T. Lavavej says in a talk that const auto && is not useful.
Isn't the following a valid use case?
NonMovableNonCopyable create () {
// ...
return {};
}
const auto && obj = create ();
Concrete application: In XLL code, MS Excel generally does not like its xlopers to be copied or moved which it returns, since after copying or moving it will not be able to correctly free them.
Instead of
const auto && obj = create ();
... write just
const auto object = create();
... or
const auto object{ create() };
The = relies on the compiler eliding the copy constructor call, but I don't know about any extant compiler that fails to do that.
The clarity gained is IMO much more important than the guarantee offered by the reference (and if using reference, do use an ordinary & reference). Namely, one avoids having a maintenance programmer wasting time on trying to understand the rationale for the reference. If the type was explicitly specified it could be a case of polymorphic reference, Petru Marginean's trick, but with auto that's out of the question, and so the maintenance programmers are left scratching their heads, for some period of paid time.
On the other hand, const T&& can be useful for function overloading as an argument type to catch the case of a temporary as argument, in the same way as && qualifier for member function was considered sufficiently useful to be adopted in the standard. For example, even though I do not recommend this, if a pointer to the actual argument is stored for later use, then presumably one doesn't want to store a pointer to a temporary, which will end up as a dangling pointer:
struct Expr{ virtual ~Expr(){} };
struct Sum_expr: Expr
{
const Expr* a_;
const Expr* b_;
Sum_expr( Expr const& a,Expr const& b ): a_( &a ), b_( &b ) {}
template< class A >
Sum_expr( A&&, Expr const&& b ) = delete;
template< class B >
Sum_expr( Expr const&& a, B&& ) = delete;
};
auto main()
-> int
{
Expr a;
Expr b;
Sum_expr sum{ a, b };
Sum_expr sum2{ a, Expr() }; //! Nope, won't compile.
}
Note: Here A&& and B&& support both rvalue and lvalue actual arguments, i.e. they're not necessarily rvalue references, because they're universal references.
But instead of overloading and differentiating the cases I think I'd make that formal argument a pointer, even if a pointer technically can be a nullpointer, because as I see it, with what I'm accustomed to, it communicates the intent more clearly.
Sum_expr( Expr const* a, Expr const* b );
Const T && is very useful if T has a mutable field. A common example is a bool m_movedFrom that's initialized to false and gets set to true when moved from. This allows the rest of your object - resource handle, for example - to remain const.
class Resource // use this as a base class of const correct classes
{
private:
mutable bool m_movedFrom;
protected:
Resource()
: m_movedFrom(false)
{
}
Resource(const Resource&& other)
: m_movedFrom(false)
{
other.m_movedFrom = true;
}
bool isOwning() const // call from descendant's destructor
{
return m_movedFrom;
}
};
EDIT: a more complicated example explaining when the object is itself const, but a global state is not (not claiming this is the good way to solve this, it's for illustrational purposes only):
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
typedef std::string object_type;
typedef std::string seek_type;
class GoalSeeker
{
private:
static std::vector<const GoalSeeker*> s_store;
const std::vector<const GoalSeeker*>::iterator m_iter;
const object_type m_data;
public:
GoalSeeker( const object_type& data )
: m_iter( s_store.insert( s_store.end(), this ) ), m_data(data)
{
}
GoalSeeker( const GoalSeeker& ) = delete;
GoalSeeker( const GoalSeeker&& other )
: m_iter( other.m_iter ), m_data( other.m_data )
{
*m_iter = this;
}
~GoalSeeker()
{
if( *m_iter == this )
{
// cleanup m_data
}
}
static bool seek( const seek_type& needle )
{
return std::find_if(s_store.begin(), s_store.end(),
[&needle](const GoalSeeker* haystack)
{
return haystack->m_data.find(needle) != std::string::npos;
}) != s_store.end();
}
};
std::vector<const GoalSeeker*> GoalSeeker::s_store = {};
GoalSeeker fn()
{
return GoalSeeker("def");
}
int main() {
GoalSeeker a( "abc" );
GoalSeeker b( "cde" );
GoalSeeker s( (const GoalSeeker&&) fn() );
std::cout << GoalSeeker::seek( "de" ) << " " << GoalSeeker::seek( "fff" );
}

homogenous containers, derived classes, initializer lists and move semantics

I have code that makes use of some dirty tricks to make it appear as what I believe is a nice interface. The most important class, Worker, is designed to make the caller construct it with temporaries; the constructor will then take them. I think the code is self-explanatory:
#include <iostream>
#include <vector>
#include <memory>
using namespace std;
struct Base
{
virtual void
print
( void )
{
cout << "Base" << endl;
};
};
struct Derived1 : public Base
{
virtual void
print
( void )
{
cout << "Derived1" << endl;
};
};
struct Derived2 : public Base
{
virtual void
print
( void )
{
cout << "Derived2" << endl;
};
};
class Worker
{
private:
/* Arrays can't hold references, and
* vectors are homogenous, so the
* only option is to use (smart) pointers. */
vector< unique_ptr<Base> >
V
;
/* The dirty trick I spoke about. */
template<typename T> void
init
( T && t )
{
V.emplace_back( new T( forward<T>(t) ) );
return;
};
template<typename T , typename ... U> void
init
( T && t , U && ... u )
{
V.emplace_back( new T( forward<T>(t) ) );
/* The usage of std::move() is explained below. */
init(move(u)...);
return;
};
public:
template<typename ... T>
Worker
( T && ... t )
{
/* Use std::move() because, inside the body
* of the function, the arguments are lvalues.
* If I hadn't put std::move(), the compiler
* would complain about an attempt of using
* _new_ with a reference type (above). */
init(move(t)...);
return;
};
void
work
( void )
{
for ( const auto & x : V )
x->print();
return;
};
};
int
main
( void )
{
/* The goal: be able to create an instance of Worker
* passing temporaries to the constructor. No initializer_list
* is involved, no copies are made; clean, fast moves. */
Worker worker{ Derived1() , Base() , Derived2() };
/* This should print "Derived1\nBase\nDerived2\n". */
worker.work();
return 0;
}
Even though it compiles fine (g++ 4.8.1) and works out of the box, I feel this is not the best way to achieve my goals, and I'd like to get rid of that annoying feeling. Has anyone found another workaround for this? Are there any better aproaches, any disadvantages with my design?
Thanks in advance. The code should compile just fine, and show how I'd like my interface to be designed and why I've made use of those "tricks". Best regards,
Kalrish
Though I still think this question better belongs to Code Review, here's an alternative version for your "dirty trick"
template < typename T >
int emplace_back(T&& t)
{
V.emplace_back( std::forward<T>(t) );
return 0;
}
template<typename ... T>
Worker
( T && ... t )
{
auto i = {emplace_back(new T{forward<T>(t)})...};
};
Or, if you want to get rid of that member function:
public:
template<typename ... T>
Worker
( T && ... t )
{
using up = std::unique_ptr<Base>;
auto f = [&](up&& p)
{ V.emplace_back(std::move(p)); return 0; };
auto i = {f( up{new T{forward<T>(t)}} )...};
};
You might get a warning because i is unused, though. This variable is only required to build an initializer-list, where a pack-expansion is allowed.
Normally, I'd suggest using an initializer-list instead of the variadic template ctor (that's what they're made for), but they don't support moving out the elements as they don't own their storage.
The same problem occurs if you want to initialize the vector in the mem-initializer-list of the ctor (via pack expansion like in the alternative above).

Wrapping C functions in auto objects without code duplication

In C++03, when you were to wrap a bunch of C functions in a class to create an 'auto object', you had to customize the object to the type of functions it encapsulated. As an example, to wrap a windows file HANDLE, you needed to call CloseHandle() in the destructor and CreateFile() in the constructor. The constructor would need to mimic the function signature of the CreateFile() function, sans the file HANDLE variable (since it's being managed).
Anyway, what I'd like to know is if it's possible to use the new features of C++11 to create a single generic class that can be used to wrap any type of resource by only providing an implementation for creation and deletion?
One problem I foresee is that the creation function, such as noted above with CreateFile(), can taken any number of parameters. Is there a way to auto-magically generate a templated constructor that mimics the signature of the function? Variadic Parameters come to mind, but I have not yet used them.
Has anyone tried writing something like this?
EDIT: Some code to help illustrate (pseudo):
template<typename Res, FunctionPtrToCreatorFunc Func, typename... Arguments>
class creator
{
public:
operator()(Res &r, Arguments... Args)
{
Func(r, /*use args?*/ Args); // Allocate resource, ie. CreateFile(r, args)
}
};
template<typename Res, FunctionPtrToDeleterFunc Func>
class deleter
{
operator()(Res &r)
{
Func(r); // delete the resource, ie. CloseHandle(r)
}
};
Then this will be the implementation of my super auto object:
template<typename Res, typename Creator, typename Deleter>
class auto_obj
{
public:
auto_obj(/*somehow copy Args from Creator class?*/)
{
Creator(_res, /*args?*/);
}
~auto_obj()
{
deleter(_res);
}
Res _res;
};
Yes, this has a similar structure to shared_ptr or unique_ptr, but instead the constructor will be the one that creates the resources by developer written creator and deleter classes. I have a feeling that std::bind may play a role in this, but I have never used it.
Here is a stab at it:
#include <utility>
#include <type_traits>
#include <cstddef>
A more friendly way to wrap up a function. I move the signature boilerplate to this template, instead of messing up the actual RAII class below. This also allows full fledged function objects to be used, as well as functions, in the RAII class below:
template< typename FuncSig, FuncSig func >
struct Functor {
template<typename... Args>
auto operator()(Args&&... args) const
-> decltype( func(std::forward<Args>(args)...) )
{ return ( func(std::forward<Args>(args)...) ); }
};
One operation that is needed for more than basic functionality is the ability to "null" a handle, allowing invalid handles to exist, and allowing handles to be moved around. Zeroer is my default function object for "null"ing a handle:
struct Zeroer {
template<typename T>
void operator()( T& t ) const {
t = 0;
}
};
RAII_handle herself. You pack the creation and destruction signatures into it, and it forwards construction to the underlying data. .close() lets you close the RAII_handle early, which is a common requirement in practice. You access the underlying data via operator* or operator->, and while this makes it look pointer-like, RAII_handle does not obey pointer semantics. It is a move-only type.
template< typename T, typename Creator, typename Destroyer, typename Nuller=Zeroer >
struct RAII_handle {
RAII_handle( std::nullptr_t ):
data()
{
Nuller()(data);
}
RAII_handle( RAII_handle const& ) = delete;
RAII_handle( RAII_handle && o ):data(std::move(o.data)) {
Nuller()(o.data);
}
RAII_handle& operator=( RAII_handle const& ) = delete;
RAII_handle& operator=( RAII_handle && o ) {
data = std::move(o.data);
Nuller()(o.data);
return *this;
}
template<typename... Args>
RAII_handle( Args&&... args ):
data( Creator()(std::forward<Args>(args)...) )
{}
auto close()->decltype( Destroyer()(std::declval<T&>()) ) {
auto retval = Destroyer()(data);
Nuller()(data);
return retval;
}
~RAII_handle() {
close();
}
T& get() { return data; }
T const& get() const { return data; }
T& operator*() { return get(); }
T const& operator*() const { return get(); }
T* operator->() { return &get(); }
T const* operator->() const { return &get(); }
private:
T data;
};
Now, some test code. My file handles will be unsigned char, and opening/closing will simply test if things are not working right.
#include <iostream>
typedef unsigned char HANDLE;
HANDLE CreateFile( char const* name ) {
std::cout << name << "\n";
return 7;
}
bool CloseFile( HANDLE h ) {
if (h) {
--h;
std::cout << (int)h << "\n";
return true;
} else {
std::cout << "already closed\n";
return true;
}
}
Once you have your open/close functions or function objects, here is how you make the type of the FileHandle:
typedef RAII_handle< HANDLE, Functor< HANDLE(*)( char const* ), CreateFile >, Functor< bool(*)(HANDLE), CloseFile > > FileHandle;
You can support entire overload sets by simply creating a function object that forwards to a fixed function name, instead of to a fixed function pointer. Basically take Functor above, remove the template signature and pointer, and replace the use of func with actual use of your function name.
Suddenly your function object represents not calling one function, but calling an entire overload set.
Fancier work can even support multiple functions, allowing one function object to support calling either CreateFile or CreateFileEx depending on what arguments are passed in.
And here is our trivial test code:
int main() {
FileHandle bob("hello.txt");
HANDLE value = *bob; // get the HANDLE out of the FileHandle
bob.close(); // optional, to close early
}
Requirements: your CloseFile must accept Nuller()(std::declval<T&>()) and not behave badly. The default Nuller()(...) just assigns zero to your T, which works for many handle types.
It supports move semantics, allowing you to return these from a function, but I didn't include a Copier argument (which I'd expect would be required for any RAII objects that can be copied).
Live example with very slightly different code.