From boris at kolpackov.net Fri Apr 2 15:51:46 2004 From: boris at kolpackov.net (Boris Kolpackov) Date: Fri Apr 2 15:46:59 2004 Subject: c++: smart auto_ptr Message-ID: <20040402215146.GB12479@kolpackov.net> Good day, Here is the problem. We want to write template class auto_ptr that supports both invasive and non-invasive reference counting. Here is an example: struct counter {}; struct foo : counter {}; struct bar {}; auto_ptr foo_p; // uses invasive counter auto_ptr bar_p; // uses non-invasive counter Of course we don't want to limit ourselves to only one predefined type of invasive counter. In other words this should work too: struct my_counter {}; struct baz : my_counter {}; auto_ptr baz_p; // uses invasive my_counter So how do we go about implementing this? The first idea may be to specialize auto_ptr for different invasive counters and leave non- specialized implementation to handle the non-invasive case: template struct auto_ptr { auto_ptr () { cerr << "non-invasive" << endl; } }; template <> struct auto_ptr { auto_ptr () { cerr << "counter" << endl; } }; template <> struct auto_ptr { auto_ptr () { cerr << "my_counter" << endl; } }; Looks good, right? The only problem with this approach is that it doesn't work. Consider, for example, this: auto_ptr bar_p; Which specialization will be used? The truth is that the primary non-specialized version will be used. Why? Because parameterization inhibits conversion. In our case c++ prefers instantiation of the primary template with x = bar to implicit conversion of bar to counter and instantiation of specialization with x = counter. And this makes sense. So does it mean we cannot do what we want? The answer is we can but we will need far more trickier meta-programming techniques and a c++ compiler that supports typeof keyword (e.g. GNU g++ or Intel c++). Here is how we can do this. The main task is to write a type function that for each argument X returns either * a type from predefined (but open for extensions) set of types if x is implicitly-convertible to one of them * x otherwise Such type function will allow us to distinguish between all invasive cases and the non-invasive case. Suppose we have such a function: template struct type { typedef ... r; }; How can we use it to achieve what we want? Here is how. First of all we will need a helper class that will encapsulate counter management. We will call it a counter management unit or cmu: template struct cmu; Now we will use cmu in auto_ptr implementation and that's where we take advantage of the type function: we instantiate cmu with the invasive counter type, not x (well, it will be x if it is the non-invasive case). template struct auto_ptr { cmu::r> cmu_; }; Do you see how everything falls into places? Now we can specialize cmu for whatever counter type we want: template <> struct cmu { cmu () { cerr << "counter" << endl; } }; The trickiest part is the type function. I guess it is easier to show the code since it speaks for itself. template x test (...); template counter test (counter*); template struct type { typedef typeof (test (reinterpret_cast (0))) r; }; The technique is explained in details in both "C++ Templates" and "Modern C++ Design". In order to extend our design with a new counter type we need to do two things: add another test function and specialize cmu. template my_counter test (my_counter*); template <> struct cmu { cmu () { cerr << "my_counter" << endl; } }; Let's now put everything together and see how it work: int main () { auto_ptr i_p; auto_ptr bar_p; auto_ptr c_p; auto_ptr foo_p; auto_ptr m_p; auto_ptr baz_p; } This program prints the following non-invasive non-invasive counter counter my_counter my_counter which is what we would expect. Attached is the complete source code. hth, -boris -------------- next part -------------- A non-text attachment was scrubbed... Name: test.cxx Type: text/x-c++src Size: 1311 bytes Desc: not available Url : http://www.kolpackov.net/pipermail/notes/attachments/20040402/e11e5f38/test.cxx -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 652 bytes Desc: Digital signature Url : http://www.kolpackov.net/pipermail/notes/attachments/20040402/e11e5f38/attachment.bin From boris at kolpackov.net Fri Apr 9 15:18:36 2004 From: boris at kolpackov.net (Boris Kolpackov) Date: Fri Apr 9 15:16:28 2004 Subject: c++: constructor template Message-ID: <20040409201836.GA23405@kolpackov.net> Good day, There is this interesting technique (or idiom, if you please) that I found a really elegant example of. The code explains it: class auto_lock { template static void unlock (void* p) { reinterpret_cast (p)->unlock (); } public: template auto_lock (x& m) : m_ (reinterpret_cast(&m), unlock_ (&unlock) { m.lock (); } ~auto_lock () { unlock_ (m_); } private: void* m_; void (*unlock_) (void*); }; -boris -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 652 bytes Desc: Digital signature Url : http://www.kolpackov.net/pipermail/notes/attachments/20040409/850687ef/attachment.bin From boris at kolpackov.net Wed Apr 21 14:35:29 2004 From: boris at kolpackov.net (Boris Kolpackov) Date: Wed Apr 21 15:12:12 2004 Subject: c++: notes on namespace In-Reply-To: <20040223222837.GA17775@kolpackov.net> References: <20040223222837.GA17775@kolpackov.net> Message-ID: <20040421193529.GA2106@kolpackov.net> Some time ago I wrote: > @@ Namespace models: 'flat' (like std::) and 'tree' (with nested > namespaces). > > > @@ A 'tree' model can potentially be transformed into a 'flat' > model via using-directives. > > > @@ In the 'tree' model the outer namespace is usually for name- > clash avoidance; the inner namespaces are for the concept > grouping. Recently I discovered one interesting advantage of the tree model over the flat model: when you say using namespace std; you make all names in the standard library accessible from this point. When you say using namespace std::mm; you know you have access only to memory-management-related names. In other words, it feels more comfortable to use using-directive in a tree-like namespace organization that in a flat one. -boris -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 652 bytes Desc: Digital signature Url : http://www.kolpackov.net/pipermail/notes/attachments/20040421/181c61f0/attachment.bin