c++ - Abstract base class for use with smart pointers (intrusive_ptr) - handling inheritance, polymorphism, cloneability and returning from factory methods -


requirements

  1. i writing class called rcobject, stands "reference counted object";
  2. the class rcobject should abstract, serving base class of framework (ec++3 item 7);
  3. creating instances of rcobject subclasses on stack should prohibited (mec++1 item 27);

    [ added: ]

    [ assume bear concrete subclass of rcobject ]

    [ c.e. here means compilation error ]

    bear b1;                        // triggers c.e. (by using mec++1 item 27) bear* b2;                       // not allowed no way trigger c.e. intrusive_ptr<bear> b3;         // recommended  bear* bs1 = new bear[8];                   // triggers c.e. container< intrusive_ptr<rcobject> > bs2;  // recommended intrusive_ptr_container<rcobject> bs3;     // recommended  class someclass { private:     bear m_b1;                 // triggers c.e.     bear* m_b2;                // not allowed no way trigger c.e.     intrusive_ptr<bear> m_b3;  // recommended }; 
  4. clarified: declaring / returning raw pointers rcobject (and subclasses) should prohibited (unfortunately, don't think there exists practical way enforce it, i.e. triggering compilation errors when users not follow). see example source code in item 3 above;

  5. instances of rcobject subclasses should cloneable cloneable in java. (mec++1 item 25);
  6. users subclassing rcobject should able write "factory methods" subclasses. there should no memory leak if returned value ignored (not assigned variable). mechanism close autorelease in objective-c;

    [ added: cschwan , kos pointed out returning "smart-pointer-to-rcobject" sufficient fulfill requirement. ]

  7. clarified: instances of rcobject subclasses should able contained in appropriate std:: or boost:: container. need "std::vector-like" container, "std::set-like" container , "std::map-like" container. baseline that

    intrusive_ptr<rcobject> my_bear = v[10]; 

    and

    m["john"] = my_bear; 

    work expected;

  8. the source code should compilable using c++98 compiler limited c++11 support (visual studio 2008 , gcc 4.6, exact).

more information

class definitions

namespace zoo {     class rcobject { ... };                  // abstract     class animal : public rcobject { ... };  // abstract     class bear : public animal { ... };      // concrete     class panda : public bear { ... };       // concrete } 

"non-smart" version - createanimal() [factory method]

zoo::animal* createanimal(bool isfacingextinction, bool isblackandwhite) {     // wish call result->autorelease() @ end...     zoo::animal* result;      if (isfacingextinction) {         if (isblackandwhite) {             result = new panda;         } else {             result = new bear;         }     } else {         result = 0;     }      return result; } 

"non-smart" version - main()

int main() {     // part 1 - construction     zoo::rcobject* object1 = new zoo::bear;     zoo::rcobject* object2 = new zoo::panda;     zoo::animal* animal1 = new zoo::bear;     zoo::animal* animal2 = new zoo::panda;     zoo::bear* bear1 = new zoo::bear;     zoo::bear* bear2 = new zoo::panda;     //zoo::panda* panda1 = new zoo::bear;  // should fail     zoo::panda* panda2 = new zoo::panda;      // creating instances of rcobject on stack should fail following     // method described in book mec++1 item 27.     //     //zoo::bear b;                         // should fail     //zoo::panda p;                        // should fail      // part 2 - object assignment     *object1 = *animal1;     *object1 = *bear1;     *object1 = *bear2;     //*bear1 = *animal1;                   // should fail      // part 3 - cloning     object1 = object2->clone();     object1 = animal1->clone();     object1 = animal2->clone();     //bear1 = animal1->clone();            // should fail      return 0; } 

"smart" version [incomplete!]

/* todo: how write factory method? should returned? */  #include <boost/intrusive_ptr.hpp>  int main() {     // part 1 - construction     boost::intrusive_ptr<zoo::rcobject> object1(new zoo::bear);     boost::intrusive_ptr<zoo::rcobject> object2(new zoo::panda);     /* ... skip (similar statements) ... */     //boost::intrusive_ptr<zoo::panda> panda1(new zoo::bear); // should fail     boost::intrusive_ptr<zoo::panda> panda2(new zoo::panda);      // creating instances of rcobject on stack should fail following     // method described in book mec++1 item 27. unfortunately, there     // doesn't exist way ban user declaring raw pointer     // rcobject (and subclasses), relies self discipline...     //     //zoo::bear b;                         // should fail     //zoo::panda p;                        // should fail     //zoo::bear* pb;                       // no way ban     //zoo::panda* pp;                      // no way ban      // part 2 - object assignment     /* ... skip (exactly same "non-smart") ... */      // part 3 - cloning     /* todo: how write this? */      return 0; } 

the above code ("smart version") shows expected usage pattern. not sure whether usage pattern follows best practices of using smart pointers or not. please correct me if doesn't.

similar questions

references

  • [ ec++3 ]: effective c++: 55 specific ways improve programs , designs (3rd edition) scott meyers
    • item 7: declare destructors virtual in polymorphic base classes

  • [ mec++1 ]: more effective c++: 35 new ways improve programs , designs (1st edition) scott meyers
    • item 25: virtualizing constructors , non-member functions
    • item 27: requiring or prohibiting heap-based objects.

articles

  • [ atomic ]: usage examples of boost::atomic - boost.org

  • [ cp8394 ]: smart pointers boost code - codeproject
    • [ section ]: intrusive_ptr - lightweight shared pointer

  • [ drdobbs ]: base class intrusively reference-counted objects in c++ - dr. dobb's

make_shared creates instance of class in same allocation block reference counter. unsure why think intrusive_ptr have better performance: great when there reference counting machinery cannot remove, not case here.

for clone, implement free function takes smart pojnter , returns same. friend, , calls private pure virtual clone method in base returns shared pointer base, fast smart pointer cast shared pointer derived. if prefer clone method, use crtp duplicate (giving private clone name secret_clone). gives covariant smart pointer return types little overhead.

crtp range of base classes has pass both base , derived classes in. crtp class derives base , has usual self() returns derived.

factory functions should return smart pointer. can use custom deleter trick pre-destroy methid call last cleanup.

if paranoid, can block ways raw pointer or reference class: block operator* on smart pointer. route raw class explicit call operator->.

another approach consider unique_ptr , references same. need shared ownership , lifetime management? make problems simpler (shared ownership).

note dangling weak pointers prevent memory make shared bring recycled.

a serious downside using smart pointers cannot have stack instances or instances directly inside containers. both of these can serious performance gains.


Comments

Popular posts from this blog

sql - VB.NET Operand type clash: date is incompatible with int error -

SVG stroke-linecap doesn't work for circles in Firefox? -

python - TypeError: Scalar value for argument 'color' is not numeric in openCV -