[inplace_factory] Question about nplace_factory

Hello, I'm trying to use inplace factories on a class that performs small object optimization. If the user code pass me an inplace factory and the optimization can be done, everything is fine, but how should I handle the case in which the optimization cannot be done? Can inplace factory export an other method, that will invoke new T() with the appropriate parameters and return the pointer to it? I can't see how to do this transparently without inplace factory support, because I don't know a way to call the correct operator new if it is defined in the class ( T::operator new(sizeof(T)) works only if T declares the operator ). Corrado -- __________________________________________________________________________ dott. Corrado Zoccolo mailto:zoccolo@di.unipi.it PhD - Department of Computer Science - University of Pisa, Italy -------------------------------------------------------------------------- The self-confidence of a warrior is not the self-confidence of the average man. The average man seeks certainty in the eyes of the onlooker and calls that self-confidence. The warrior seeks impeccability in his own eyes and calls that humbleness. Tales of Power - C. Castaneda

Hi Corrado,
Can inplace factory export an other method, that will invoke new T() with the appropriate parameters and return the pointer to it?
It clearly could, though it worries me than in that case it wouldn't be an "in-place" factory but just a ordinary factory. While I can understand your need from your side, specially assuming that the pointer is an implementation detail, it feels a bit of a hack from the in-place factory POV.
I can't see how to do this transparently without inplace factory support, because I don't know a way to call the correct operator new if it is defined in the class ( T::operator new(sizeof(T)) works only if T declares the operator ).
I'm getting rusty on C++ lately writting so much C# and Ruby code, but IIRC typical implementations of new call malloc() then in place new, so, couldn't you do the same? (I don't recall if malloc() itself or the implementation of new takes care of alignment.... damn, I'm getting old :) HTH -- -------- Fernando Cacciola SciSoft http://certuscode.wordpress.com http://fcacciola.50webs.com http://fcacciola.wordpress.com

Hi Fernando,
It clearly could, though it worries me than in that case it wouldn't be an "in-place" factory but just a ordinary factory. While I can understand your need from your side, specially assuming that the pointer is an implementation detail, it feels a bit of a hack from the in-place factory POV.
Ok, but I think having it could improve in_place factory usability in several places. I'm not the only one working on a library proposal with small object optimization currently. Maybe also Steven's TypeErasure library could benefit from this.
<snip> IIRC typical implementations of new call malloc() then in place new, so, couldn't you do the same?
I can call either malloc or global new (both will give correctly aligned memory), but this will defeat class specific memory management. If operator new and delete are redefined for a given class, I'd like to (and the library user also would me to) use the redefined one. Moreover, if new/delete are redefined, the memory allocated by: void *b=::operator new (sizeof T); // memory allocated through global operator new p= new (b) T(args); // this is what in_place does cannot be deallocated by delete p; I think something like the following should work, but it seems clumsy and I still have to check: template<typename T> struct new_invoker : T { static void * alloc() { return operator new(sizeof T); } // should look up operator new in T scope before global scope static void dealloc(void *p) { return operator delete(p); } // should look up operator delete in T scope before global scope private: new_invoker(); new_invoker(new_invoker const &); void ~new_invoker(); }; // specializations for non-class types omitted Corrado -- __________________________________________________________________________ dott. Corrado Zoccolo mailto:zoccolo@di.unipi.it PhD - Department of Computer Science - University of Pisa, Italy -------------------------------------------------------------------------- The self-confidence of a warrior is not the self-confidence of the average man. The average man seeks certainty in the eyes of the onlooker and calls that self-confidence. The warrior seeks impeccability in his own eyes and calls that humbleness. Tales of Power - C. Castaneda

Hi again, I checked, and the code I posted before (here shown with small fixes to the syntax) doesn't work as I wanted, due to the two phase lookup that always finds global operator new instead of a possibly redefined one:
template<typename T> struct new_invoker : T { static void * alloc() { return operator new(sizeof(T)); } // should look up operator new in T scope before global scope static void dealloc(void *p) { return operator delete(p); } // should look up operator delete in T scope before global scope private: new_invoker(); new_invoker(new_invoker const &); ~new_invoker(); }; // specializations for non-class types omitted
-- __________________________________________________________________________ dott. Corrado Zoccolo mailto:zoccolo@di.unipi.it PhD - Department of Computer Science - University of Pisa, Italy -------------------------------------------------------------------------- The self-confidence of a warrior is not the self-confidence of the average man. The average man seeks certainty in the eyes of the onlooker and calls that self-confidence. The warrior seeks impeccability in his own eyes and calls that humbleness. Tales of Power - C. Castaneda

On Nov 18, 2007 11:09 AM, Corrado Zoccolo <czoccolo@gmail.com> wrote:
Hi again,
I checked, and the code I posted before (here shown with small fixes to the syntax) doesn't work as I wanted, due to the two phase lookup that always finds global operator new instead of a possibly redefined one:
Maybe you can use SFINAE to detect if a class implements operator new. I'm not sure if it can be done for operator new, it certainly can be done for other member functions. -- gpd

Hi Giovanni On Nov 18, 2007 1:59 PM, Giovanni Piero Deretta <gpderetta@gmail.com> wrote:
Maybe you can use SFINAE to detect if a class implements operator new. I'm not sure if it can be done for operator new, it certainly can be done for other member functions.
-- gpd
I think SFINAE is not enough to replicate faithfully the rules employed by the compiler to select the which operator new is called for an expression like new T(a1,..,an) . It will look not only in T, but also in its base classes. I solved differently, by writing an adapter around in_place_factory (that can be found attached). Basically, I create a set of classes typed_out_of_place_factory##N, each inheriting from typed_in_place_factory##N, that provide me the correct apply overload, and a template function to ease the conversion (out_of_place: typed_in_place_factory##N -> typed_out_of_place_factory##N). The only drawback of this, w.r.t. changing in_place_factory to provide this behavior, is that I have to include it always, so the preprocessor magic overhead is always paid. The other solution, the client code would include it only when it is actually used. -- __________________________________________________________________________ dott. Corrado Zoccolo mailto:zoccolo@di.unipi.it PhD - Department of Computer Science - University of Pisa, Italy -------------------------------------------------------------------------- The self-confidence of a warrior is not the self-confidence of the average man. The average man seeks certainty in the eyes of the onlooker and calls that self-confidence. The warrior seeks impeccability in his own eyes and calls that humbleness. Tales of Power - C. Castaneda

Hi Corrado,
I solved differently, by writing an adapter around in_place_factory (that can be found attached).
Which is along the lines of what I was thinking. Having "out_of_place" inherit from "in_place" is still odd IMO, so I prefer having a common "typed_factory_base" holding the parameters list from which the two versions derive (these dervied class just define the apply()). Furthermore, this is off the top of my head, but I was thinking when I first responded you that the parameter list could be stored within an aggregated struct to make it easier to convert one kind of factory into another. Best Fernando

Having "out_of_place" inherit from "in_place" is still odd IMO, so I
Hi Fernando, On Nov 18, 2007 7:55 PM, Fernando Cacciola <fernando_cacciola@hotmail.com> wrote: prefer
having a common "typed_factory_base" holding the parameters list from which the two versions derive (these dervied class just define the apply()). Yes, it was a quick hack to see if it could work.
After further thoughts along those lines: On Nov 18, 2007 7:55 PM, Fernando Cacciola <fernando_cacciola@hotmail.com> wrote:
Furthermore, this is off the top of my head, but I was thinking when I first responded you that the parameter list could be stored within an aggregated struct to make it easier to convert one kind of factory into another.
I think the best would be to have a reusable "(typed) argument list" structure, around which the factories can be built as free functions (or we could have a generic apply taking the argument list and a functor, so every factory will just become a different functor). Moreover, once the argument list is decoupled from the factory, it could be interoperable with fusion, enabling more freedom in how they are used. Corrado -- __________________________________________________________________________ dott. Corrado Zoccolo mailto:zoccolo@di.unipi.it PhD - Department of Computer Science - University of Pisa, Italy -------------------------------------------------------------------------- The self-confidence of a warrior is not the self-confidence of the average man. The average man seeks certainty in the eyes of the onlooker and calls that self-confidence. The warrior seeks impeccability in his own eyes and calls that humbleness. Tales of Power - C. Castaneda

Hi Corrado,
I think the best would be to have a reusable "(typed) argument list" structure, around which the factories can be built as free functions (or we could have a generic apply taking the argument list and a functor, so every factory will just become a different functor). Moreover, once the argument list is decoupled from the factory, it could be interoperable with fusion, enabling more freedom in how they are used.
Indeed, I agree that the best factorization is to decouple the factory applicator from the argument list. In fact, the applicator should handle a generic tuple as the argument list (with at most some custom made tuple if dependency with fusion is a problem) Now that's a major make up for the factories, though one worth doing it IMO, so the big quesion is: would you be interested in doing that yourself? Best -- Fernando Cacciola SciSoft http://fcacciola.50webs.com

Hi Fernando On Nov 19, 2007 10:20 PM, Fernando Cacciola <fernando.cacciola@gmail.com> wrote:
Hi Corrado, Indeed, I agree that the best factorization is to decouple the factory applicator from the argument list. In fact, the applicator should handle a generic tuple as the argument list (with at most some custom made tuple if dependency with fusion is a problem)
Now that's a major make up for the factories, though one worth doing it IMO, so the big quesion is: would you be interested in doing that yourself?
Sure I'm interested, but my highest priority now is to make my polymorphic value object library ready for review. When I've done with my tests and documentation, I can start working on the in_place refactorization. It needs to be handled with care, since there are already some libraries depending on the current interface, and we are going for an interface breaking change. Corrado Best
-- Fernando Cacciola SciSoft http://fcacciola.50webs.com
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
-- __________________________________________________________________________ dott. Corrado Zoccolo mailto:zoccolo@di.unipi.it PhD - Department of Computer Science - University of Pisa, Italy -------------------------------------------------------------------------- The self-confidence of a warrior is not the self-confidence of the average man. The average man seeks certainty in the eyes of the onlooker and calls that self-confidence. The warrior seeks impeccability in his own eyes and calls that humbleness. Tales of Power - C. Castaneda

AMDG Corrado Zoccolo <czoccolo <at> gmail.com> writes:
I think SFINAE is not enough to replicate faithfully the rules employed by the compiler to select the which operator new is called for an expression like new T(a1,..,an) . It will look not only in T, but also in its base classes.
I don't understand. Both "new T" and has_new<T> look in base classes of T. SFINAE seems to work on both msvc 8.0 and gcc 3.4.4 I think that what I would do is create a generic allocator that looks up the correct operator new/delete template<class T, bool = has_new<T>::value> struct my_allocator; template<class T> struct my_allocator<T, true> { T* allocate(std::size_t n) { return(T::operator new(n * sizeof(T))); } void deallocate(T* victim, std::size_t n) { return(T::operator delete(victim, n * sizeof(T))); } //... }; template<class T> struct my_allocator<T, false> { T* allocate(std::size_t n) { return(::operator new(n * sizeof(T))); } void deallocate(T* victim, std::size_t n) { return(::operator delete(victim)); } //... }; In Christ, Steven Watanabe

Hi Steven, On Nov 19, 2007 7:37 PM, Steven Watanabe <steven@providere-consulting.com> wrote:
AMDG
Both "new T" and has_new<T> look in base classes of T. SFINAE seems to work on both msvc 8.0 and gcc 3.4.4
I think that what I would do is create a generic allocator that looks up the correct operator new/delete <snipped allocator code>
I tested with this code: typedef void * (*new_signature_t)(size_t); template<typename T, T U> struct has_ { typedef T type; }; template<typename T> typename has_<new_signature_t, &T::operator new>::type get_new(T*) { return T::operator new; } new_signature_t get_new(...) { return ::operator new; } and it actually works with recent compilers like g++ 4.1.2, but it fails on g++ 3.3.5, on a simple usage like: struct A {}; int main() { A* a_= ::new( get_new((A*)0)(sizeof(A)) ) A(); return 0; } with the following error: test_alloc.cc:88: error: `operator new' is not a member of type `A' It seems that on this compiler, the substitution failure of a pointer to (static) member function is actually treated as error. Do you know some technique/workaround to make this work also on g++ 3.3? It is the compiler I'm using at work, so I'd like to support it even if it is outdated. Is there a BOOST defect macro for this behavior, to enable workarounds when the compiler cannot handle it? Thanks, Corrado -- __________________________________________________________________________ dott. Corrado Zoccolo mailto:zoccolo@di.unipi.it PhD - Department of Computer Science - University of Pisa, Italy -------------------------------------------------------------------------- The self-confidence of a warrior is not the self-confidence of the average man. The average man seeks certainty in the eyes of the onlooker and calls that self-confidence. The warrior seeks impeccability in his own eyes and calls that humbleness. Tales of Power - C. Castaneda
participants (5)
-
Corrado Zoccolo
-
Fernando Cacciola
-
Fernando Cacciola
-
Giovanni Piero Deretta
-
Steven Watanabe