C ++: creating a Shared <T> template, not a shared_ptr <T> object

In the previous question, I would like boost::shared_ptr<A> be a subclass of A (or possibly A* ) so that it can be used in methods that take A* as an argument.

Consider the following class:

 class A { public: A(int x) {mX = x;} virtual void setX(int x) {mX = x;} virtual int getX() const {return mX;} private: int mX; }; 

In a previous question, I suggested creating a SharedA object to take care of this, and apparently it does.

 class SharedA : public A { public: SharedA(A* a) : mImpl(a){} virtual void setX(int x) {mImpl->setX(x);} virtual int getX() const {return mImpl->getX();} private: boost::shared_ptr<A> mImpl; }; 

It would be Grrrrrrrreat if I could create a template class to take care of all this for me.

 template <class T> class Shared : public T { public: SharedT(T* t) : mImpl(t) { //What kind of crazy voodoo goes here? } private: boost::shared_ptr<T> mImpl; }; 

If I had this (along with the corresponding constructors in Shared<T> ), I could do the following:

 A* indestructo_A = new Shared<A>(new A(100)); A* indestructo_A_clone = new Shared<A>(indestructo_A); delete indestructo_A cout << "Indestructo-A back with a vengence!" << indestructo_A_clone.getX(); 

Questions:

  • This is useful? Or is it his utility only in corner cases when you are dealing with particularly bad code. For example:

    void aFunctionYouHaveToUse (A * a) {/ some useful algorithm, and then / delete a; }

  • Is it possible to build such a template class? (I think you need a reflection, right?) If you can build it, how?

+2
c ++ design shared-ptr pimpl-idiom
Dec 10 2018-10-10
source share
3 answers

There really is a damn good reason why shared_ptr does not allow explicit casting to A * (there are better ways to do this than inheritance, which would be impossible anyway). The whole purpose of shared_ptr and other smart pointers is to provide a small encapsulated object whose sole purpose is to own the pointer and decide when and how to delete it.

If this object allowed the same pointer to simply pass wily-nily, without thoughts, then it simply could not serve its purpose. Every time you dig into a smart pointer to get to the raw pointer inside you, you violate its semantics of ownership, and then you must be very careful not to do something stupid. Smart pointers make you think about it, forcing you to make a call to get inside the pointer inside, and not just do it quietly whenever you accidentally pass it to the wrong function. Think of it like a smart pointer saying, β€œHey, you know what you are doing, it can be dangerous, right? Well, then you are here.”

IMHO, the universe would be better if shared pointers did not allow access to their pointers. Unfortunately, this is not this universe and cannot be this universe, because sometimes you still need to pass this thing into a function that does not use smart pointers. So, since we don’t live in this better universe, OUR smart pointers allow access, they just don’t chat about it.

+8
Dec 10 '10 at 17:25
source share

There may be a way, but it's kind, dirty. You can try putting another class in your hierarchy: ABase. A can inherit from ABase, and ABase will contain standard implementations of all public methods. Something like that:

 #include <iostream> #include <boost/shared_ptr.hpp> class ABase { public: ABase() {} void init( ABase *a ) { mImpl.reset( a ); } virtual void setX( int x ) { mImpl->setX( x ); } virtual int getX() const { return mImpl->getX(); } boost::shared_ptr< ABase > mImpl; }; class A : public ABase { public: typedef ABase BaseClass; A(int x) {mX = x;} virtual void setX(int x) {mX = x;} virtual int getX() const {return mX;} private: int mX; }; template <class T> class Shared : public T::BaseClass { public: Shared(T* t) { init( t ); } }; int main() { Shared< A > sh( new A( 1 ) ); std::cout << sh.getX() << std::endl; sh.setX( 5 ); std::cout << sh.getX() << std::endl; } 

This is just a concept. I need to check the code. The main idea is to pass the default implementation, inheriting shared access not directly from type A, but from its base type, which has all the necessary implementations. The base class needs some extra work, but I think the idea is pretty clear.

This is not what you asked for (this is actually not possible), but in some cases it can be useful, and probably closest to you.

+1
Dec 10 2018-10-10
source share

Set it aside if this is a good idea. If you want a type of shared pointer that can be implicitly converted to a raw pointer, you do not need to inherit from the type of visitor or perform other similar complications. Just create a generic pointer type with the corresponding implicit conversion operators.

This can be done by inheriting or composing an existing type of shared pointer. (Or else, by making your own shared pointer from scratch).

Using inheritance, for example:

 template<typename T> class convertible_shared_ptr : public boost::shared_ptr<T> { public: convertible_shared_ptr() {} convertible_shared_ptr(T* ptr) : boost::shared_ptr<T>(ptr) {} operator T* () const { return get(); } T* operator-> () const { return get(); } }; 

Then you use this thing:

 #include <iostream> #include <boost/shared_ptr.hpp> using namespace std; class A // simple class for example purposes { public: A() : member(42) {} int member; }; void foo(A* a) { cout << "a->member=" << a->member << endl; } int main() { convertible_shared_ptr<A> ptr(new A); foo(ptr); cout << "ptr->member=" << ptr->member << endl; return 0; } 

Of course, I really have not tried such a thing in a real-world scenario. When trying to interact with the corresponding types of weak_ptr , some difficulties may arise. At the very least, another code may be needed to cover all possible uses.

0
Dec 10 2018-10-10
source share



All Articles