c++ - Forwarding to in-place constructor -


i have message class bit of pain work with, had construct message class, tell allocate space object , populate space either construction or memberwise.

i want make possible construct message object immediate, inline new of resulting object, simple syntax @ call site while ensuring copy elision.

#include <cstdint>  typedef uint8_t id_t; enum class messageid { worldpeace };  class message {     uint8_t* m_data;         // current memory     uint8_t m_localdata[64]; // upto 64 bytes.     id_t m_messageid;     size_t m_size; // amount of data used     size_t m_capacity; // amount of space available     // ...  public:     message(size_t requestsize, id_t messageid)         : m_data(m_localdata)         , m_messageid(messageid)         , m_size(0), m_capacity(sizeof(m_localdata))     {         grow(requestsize);     }      void grow(size_t newsize)     {         if (newsize > m_capacity)         {             m_data = realloc((m_data == m_localdata) ? nullptr : m_data, newsize);             assert(m_data != nullptr); // system uses less brutal mem mgmt             m_size = newsize;         }     }      template<typename t>     t* allocateptr()     {         size_t offset = size;         grow(offset + sizeof(t));         return (t*)(m_data + offset);     }  #ifdef use_cpp11     template<typename t, typename args...>     message(id_t messageid, args&&... args)         : message(sizeof(t), messageid)     {         // know m_data points large enough buffer         new ((t*)m_data) t (std::forward<args>(args)...);     } #endif }; 

pre-c++11 had nasty macro, construct_in_place, did:

#define construct_in_place(message, typename, ...) \     new ((message).allocateptr<typename>()) typename (__va_args__) 

and say:

message outgoing(sizeof(mystruct), messageid::worldpeace); construct_in_place(outgoing, mystruct, wparg1, wparg2, wparg3); 

with c++11, use

message outgoing<mystruct>(messageid::worldpeace, wparg1, wparg2, wparg3); 

but find messy. want implement is:

    template<typename t>     message(id_t messageid, t&& src)         : message(sizeof(t), messageid)     {         // know m_data points large enough buffer         new ((t*)m_data) t (src);     } 

so user uses

message outgoing(messageid::worldpeace, mystruct(wparg1, wparg2, wparg3)); 

but seems first constructs temporary mystruct on stack turning in-place new call move constructor of t.

many of these messages simple, pod, , in marshalling functions this:

void dispatchworldpeace(int wparg1, int wparg2, int wparg3) {     message outgoing(messageid::worldpeace, mystruct(wparg1, wparg2, wparg3));     outgoing.send(g_listener); } 

so want avoid creating intermediate temporary going require subsequent move/copy.

it seems compiler should able eliminate temporary , move , forward construction way down in-place new.

what doing causing not to? (gcc 4.8.1, clang 3.5, msvc 2013)

you won't able elide copy/move in placement new: copy elision entirely based on idea compiler knows @ construction time object end up. also, since copy elision changes behavior of program (after all, won't call respective constructor , destructor if have side-effects) copy elision limited few specific cases (listed in 12.8 [class.copy] paragraph 31: when returning local variable name, when throwing local variable name, when catching exception of correct type value, , when copying/moving temporary variable; see clause exact details). since [placement] new none of contexts copy can elided , argument constructor not temporary (it named), copy/move never elided. adding missing std::forward<t>(...) constructor cause copy/move elided:

template<typename t> message(id_t messageid, t&& src)     : message(sizeof(t), messageid) {     // placement new take void* anyway, i.e., no need cast     new (m_data) t (std::forward<t>(src)); } 

i don't think can explicitly specify template parameter when calling constructor. thus, think closest without constructing object ahead of time , getting copied/moved this:

template <typename> struct tag {};  template <typename t, typename a> message::message(tag<t>, id_t messageid, a... args)     : message(messageid, sizeof(t)) {     new(this->m_data) t(std::forward<a>(args)...); } 

one approach might make things bit nicer using id_t map relevant type assuming there mapping message ids relevant type:

typedef uint8_t id_t; template <typename t, id_t id> struct tag {}; struct messageid {     static constexpr tag<mystruct, 1> worldpeace;     // ... }; template <typename t, id_t id, typename... a> message::message(tag<t, id>, a&&... args)     message(id, sizeof(t)) {     new(this->m_data) t(std::forward<a>)(args)...); } 

Comments

Popular posts from this blog

html - Sizing a high-res image (~8MB) to display entirely in a small div (circular, diameter 100px) -

java - IntelliJ - No such instance method -

identifier - Is it possible for an html5 document to have two ids? -