![]() | |
![]() ![]() |
![]() | Imperfect C++ Practical Solutions for Real-Life Programming By Matthew Wilson |
Table of Contents | |
Chapter 5. Object Access Models |
5.4. Shared ObjectsWhere it is suitable, this is my favorite access model and is based around reference counting (see Listing 5.5). The container holds a reference count on the contained items and provides reference-counted pointers to the items upon request. Listing 5.5.class EnvironmentVariable { public: typedef ref_ptr<RCString> String_ref_type; // Accessors public: . . . String_ref_type GetValuePart(size_t index) { return index < m_valueParts.size() ? m_valueParts[index] : String_ref_type(0); } // Members private: Vector<String_ref_type> m_valueParts; }; With a suitably competent reference counting smart-pointer class, which we'll assume our notional ref_ptr to be, it's ridiculously easy. The semantics of the ref_ptr ensure that when copies are taken, the reference count is increased, and when instances are destroyed, the reference count is decreased. When the reference count reaches 0, the RCString instance deletes itself. This does incur a performance cost, which is generally low, but not so low as to be insignificant in very high-performing systems. Herb Sutter reports in [Sutt2002] on the results of performance tests of strings that implement reference counting and copy-on-write, which demonstrate that the reference counting can often end up being a pessimization [Sutt2002]. The scenario I've shown here is a little different, whereby it's the string object itself that is reference counted, so the performance effects may differ, but it's important to be aware of the costs of the different access models. Despite these caveats, this model is a very powerful technique, and needn't be hindered by performance concerns. I have used a reference-counting scheme on a high-speed data parser that runs on several platforms, and outperforms the previous version by an order of magnitude.[1]
This solution can even work for types that have not been built for reference counting by using a smart pointer type that brings reference-counting logic with it, such as Boost's shared_ptr. Furthermore, a reference-counted approach can be used to remove the dependency of a contained object's lifetime on that of its (original) container. For example, consider you have a component that enumerates the contents of the file system. If it uses reference counting for the data objects it uses to represent file-system entries, client code would be able to hold on to these objects for as long as they need them, rather than having to take copies of all particular file attributes they potentially need before the enumerating component is destroyed. This can have substantial cost savings. ![]() |
![]() | |
![]() ![]() |