boost::mpl::for_each and value_initialized

Dear All, what is the use of value_initialized in boost::mpl::for_each? It should be sufficient if the value is initialized by the constructor. value_initialized() calls memset() in before calling the constructor. This memset() is not being optimized away with gnu-c++ 4.4.1. What class does require zeroed memory to work correctly? Peter *** boost_1_40_0/boost/mpl/for_each.hpp Mon Aug 17 22:16:53 2009 --- boost_1_40_0.saved/boost/mpl/for_each.hpp Tue Sep 1 12:54:55 2009 *************** *** 71,78 **** // dwa 2002/9/10 -- make sure not to invoke undefined behavior // when we pass arg. ! value_initialized<arg> x; ! aux::unwrap(f, 0)(boost::get(x)); typedef typename mpl::next<Iterator>::type iter; for_each_impl<boost::is_same<iter,LastIterator>::value> --- 71,78 ---- // dwa 2002/9/10 -- make sure not to invoke undefined behavior // when we pass arg. ! //value_initialized<arg> x; ! aux::unwrap(f, 0)(arg()); typedef typename mpl::next<Iterator>::type iter; for_each_impl<boost::is_same<iter,LastIterator>::value>

"Peter Foelsche" <peter_foelsche@agilent.com> wrote in message news:h7jv3a$n4n$1@ger.gmane.org...
i second that... ...msvc++ 8.0 and 9.0 ("with all available optimizations and maximum inlining depth") are also "unable" to remove the redundant memset() call (it is only sometimes replaced with an intrinsic implementation)... there was a somewhat related discussion ( http://lists.boost.org/Archives/boost/2004/02/61582.php ) dealing, among other things, with the problem of default construction in mpl::for_each ... in the current implementation you must either pay for default construction or pay for added verbosity/ugliness of the "wrap" approach... ...i must admit i did not quite understand the argument of Aleksey Gurtovoy that the proposed "aux::unwrap(f, 0)::operator()<arg>()" solution would "would rule out ordinary function objects" (can you even use them with mpl::for_each?) and that "it's not portable" (the ::operator()<arg>() syntax is not standard?)... (apologies if this should go to a seperate thread...it seemed related enough :) -- "That men do not learn very much from the lessons of history is the most important of all the lessons of history." Aldous Huxley

On Wed, 02 Sep 2009 04:11:12 -0500, Domagoj Saric <domagoj.saric@littleendian.com> wrote:
Yep. I provided an example in the message you are referring to above: typedef mpl::range_c<int,0,10> numbers; std::vector<int> v; mpl::for_each<numbers,mpl::_>( boost::bind(push_back, &v, _1) );
and that "it's not portable" (the ::operator()<arg>() syntax is not standard?)...
Standard != portable in practice. -- Aleksey Gurtovoy MetaCommunications Engineering

"Aleksey Gurtovoy" <agurtovoy@meta-comm.com> wrote in message news:op.uzp6h4quccf1k7@wonderland.office.meta...
Yep. I provided an example in the message you are referring to above:
i'm sorry, missed it somehow...
true this does actually compile and work...but i still don't understand how :) because (as far as i understand) mpl::for_each feeds mpl::int_ objects not POD ints to the functor (created with bind) in the above case and the functor expects and accepts only POD ints (not mpl::int_s)...
true but..hmm..we are talking mpl here :) i'd suspect that pretty much eliminates a lot of 'too' defficient compilers...perhaps a 'dual' approach can be taken like in boost::function where you have one 'proper' syntax and a 'backup'/different one for non-conformant compilers... the status quo design penalizes 'those with a 'good enough' compiler' in terms of verbosity (thus probably even sligthtly in terms of compilation time, if you do the sequence transformation step proposed by David Abrahams) and/or efficiency (unused object construction) because of those with a 'defficient' compiler...considering the freely available gcc and msvc++ (express) that are 'good enough' this decision does not seem justified imho (ofcourse if we do not take the argument of 'ordinary function objects' into account)... perhaps 'typed null pointers' could be passed..? anyway it would be usefull if the final design decision would make it to the official documentation with an explanation to prevent further resurrection of this topic ;) -- "That men do not learn very much from the lessons of history is the most important of all the lessons of history." Aldous Huxley

just to sort answer my self publicly in case someone else wondered the same thing/managed not to see it clearly stated in the documentation: that mpl integral constants provide implicit conversion operators... -- "That men do not learn very much from the lessons of history is the most important of all the lessons of history." Aldous Huxley

Hi Peter,
what is the use of value_initialized in boost::mpl::for_each? It should be sufficient if the value is initialized by the constructor.
In theory, yes. In practice, at the time when the code was authored, it wasn't -- see http://www.boost.org/doc/libs/1_40_0/libs/utility/value_init.htm
value_initialized() calls memset() in before calling the constructor.
Apparently this change was introduced in 1.35 release: "New versions of value_initialized (Boost release version 1.35 or higher) offer a workaround to these issues: value_initialized will now clear its internal data, prior to constructing the object that it contains." The fact that it's done unconditionally (as opposite only for compilers with the discussed issues) is IMHO a bug.
This memset() is not being optimized away with gnu-c++ 4.4.1.
My preferred way of addressing this would be to fix value_initialized by #ifdef-ing the memset to be present for the faulty compilers only. Could you verify whether the gcc will optimize away the rest of the value_initialized magic if the memset is out? -- Aleksey Gurtovoy MetaCommunications Engineering

"Aleksey Gurtovoy" <agurtovoy@meta-comm.com> wrote in message news:op.uzp57jgyccf1k7@wonderland.office.meta...
Could you verify whether the gcc will optimize away the rest of the value_initialized magic if the memset is out?
Ok -- I removed memset from value_initialized and I restored for_each.hpp to is original state. Now gcc 4.4.1 with optimization also does not create any (assembler) code for the initialization of this anyway not used parameter.

on Fri Sep 04 2009, "Aleksey Gurtovoy" <agurtovoy-AT-meta-comm.com> wrote:
Agreed. Is this being fixed? -- Dave Abrahams BoostPro Computing http://www.boostpro.com

"Aleksey Gurtovoy" <agurtovoy@meta-comm.com> wrote in message news:op.uzp57jgyccf1k7@wonderland.office.meta... > Hi Peter, > >> what is the use of value_initialized in boost::mpl::for_each? >> It should be sufficient if the value is initialized by the constructor. > > In theory, yes. In practice, at the time when the code was authored, > it wasn't -- see > http://www.boost.org/doc/libs/1_40_0/libs/utility/value_init.htm But why the insistence on _value_ initialization? Was it ever explicitly demanded by someone? Default initialization is, AFAIK, a perfectly standard C++ language construct that, unlike value initialization, is not broken across compiler implementations. So: >> value_initialized<arg> x; >> aux::unwrap(f, 0)(boost::get(x)); - suffers from runtime and/or compile time performance issues (while providing a certain 'defensive programming safe guard' for 'reckless programming'/not knowing the difference between default and value initialization...but this IMO should never take precedence over the 'you do not pay for what you do not use' 'directive'...'this' is not a 'managed' C#/Java environment after all...) >> aux::unwrap(f, 0)(arg()); - suffers from 'possible undefined behaviour' and the 'sequence of array types' and l/r-value issues >> arg x; >> aux::unwrap(f, 0)(x); - suffers from none of the above...only the mpl::for_each documentation must be changed to explicitly state that the objects passed are default, not value, initialized...and when the value_initialized<> wrapper along with the boost::get() call are eliminated the compiler will have a much better chance of detecting that the passed object is actually not used (and then removing it all together)... Furthermore why to even pass default constructed objects? Why would the desire/need to iterate over a sequence of types ever imply that one also wants instances of default constructed objects of those types? If the only argument is the support for plain function objects that can also be achieved with typed null pointers. Or...maybe all of this can be made a matter of policy... -- "That men do not learn very much from the lessons of history is the most important of all the lessons of history." Aldous Huxley

"Domagoj Saric" <dsaritz@gmail.com> wrote in message news:hkn7c1$oq0$1@ger.gmane.org... >>> aux::unwrap(f, 0)(arg()); > - suffers from 'possible undefined behaviour' The above should have said "suffers from possible buggy/non-standard behaviour'. >>> arg x; >>> aux::unwrap(f, 0)(x); > - suffers from none of the above... The above should have said "does not suffer from buggy/non-standard behaviour but from the problem of undefined behaviour inherent in default initialization" which, IMO, is only an issue if you want to protect programmers that 'forget the difference between default initialization and value initialization' (by making 'managing' the issue for them, i.e. making everyone pay in performance)... Anyways...it crossed my mind that writing the lines in question like this: aux::unwrap(f, 0)( boost::get( value_initialized<arg>() ) ); might help some compilers to eliminate the unused temporary objects...and as I went to test it with MSVC++ 9.0 in my real life project I found that now (without the mentioned change, with original boost 1.40 code), somehow, MSVC++ 9.0 SP1 completely optimizes away the entire value_initialized-related code...both the object constructor and the preceding memset... I remember testing the issue with MSVC++ 8.0 and 9.0 when this whole discussion began and reporting that the mentioned compilers were unable to optimize away the memsets (with any level of optimization)...and I really can't remember what could be the change that triggered/enabled the new/'wanted' behaviour (maybe I installed SP1 after the original test)... The code in question 'iterates' over a type list of ~40-50 classes with non-trivial (but non-throwing) constructors and trivial destructors and the functor is rather complex [involving GUI constructions (based solely on static information from the classes thus w/o need for object instances) and thus exception throwing]... The above reminds me of another/'worst case' scenario for the "value_initializing for_each" issue: if the classes in the type list have non-trivial destructors and the functor can throw the compiler will, along with the rest of the already mentioned baggage, also insert implicit try-catch blocks... -- "That men do not learn very much from the lessons of history is the most important of all the lessons of history." Aldous Huxley
participants (5)
-
Aleksey Gurtovoy
-
David Abrahams
-
Domagoj Saric
-
Domagoj Saric
-
Peter Foelsche