
Vladimir Batov wrote:
shared_ptr is an extremely versatile and poweful gadget. One (among others) thing it handles well is incomplete classes for implementation hiding. Maybe there are other smart pointers doing that sort of thing cheaper. I am not sure.
Here is a simple deep-copying smart pointer. template<typename T> struct copy_ptr { copy_ptr() : ptr(0) { } explicit copy_ptr(T* ptr_) : ptr(ptr_) { } ~copy_ptr() { delete ptr; } copy_ptr(const copy_ptr& p) ptr(p.ptr ? new(ptr) T(*p.ptr) : 0) { } copy_ptr& operator=(const copy_ptr& p) { if(ptr) { if(p.ptr) { *ptr = *p.ptr; } else { delete ptr; ptr = 0; } } else if(p.ptr) { new(ptr) T(*p.ptr); } } void swap(copy_ptr& p) { T* tmp = ptr; ptr = p.ptr; p.ptr = ptr; } T* operator->() { return ptr; } const T* operator->() const { return ptr; } T& operator*() { return *ptr; } const T& operator*() const { return *ptr; } T* get() { return ptr; } const T* get() const { return ptr; } private: T* ptr; }; Could hardly be simpler and more lightweight. (Well, not allowing null pointers would certainly simplify it actually) That is nothing compared to the massive overhead of using shared_ptr.
You want your implementation details to be shared across all 'Test's? What you need is more like a deep-copying smart pointer.
It certainly depends on application. Like if I have a GUI widget, then I do not want to deep-copy it. If I have static read-only configuration data, I do not want deep-copying those either.
Deep-copying vs. shallow-copying is a separate issue that is likely to be addressed via an additional policy template parameter. I did not want to blow up my example with all the bells and whistles for smaller code foot-print and so that the main idea stands out clearer.
When you copy an object, modifying the copy shouldn't trigger any visible side-effect in the original one. That is why sharing implementation details can only be done if data is read-only. Thus, shallow-copy certainly cannot be applied by default : it's implementation dependent ; so it's no good for something that's supposed to be a generic idiom for implementations. There is no need for a policy either, since you could just use shared_ptr in your implementation type if you want something to be shared and not copied. (that actually gives you more flexibility for the implementation than setting a policy in the interface, which would set the ABI) So you just need a deep-copying smart pointer like the one I provided earlier.