c++ - Why do std::shared_ptr<void> work -


i found code using std::shared_ptr perform arbitrary cleanup @ shutdown. @ first thought code not possibly work, tried following:

#include <memory> #include <iostream> #include <vector>  class test { public:   test() {     std::cout << "test created" << std::endl;   }   ~test() {     std::cout << "test destroyed" << std::endl;   } };  int main() {   std::cout << "at begin of main.\ncreating std::vector<std::shared_ptr<void>>"              << std::endl;   std::vector<std::shared_ptr<void>> v;   {     std::cout << "creating test" << std::endl;     v.push_back( std::shared_ptr<test>( new test() ) );     std::cout << "leaving scope" << std::endl;   }   std::cout << "leaving main" << std::endl;   return 0; } 

this program gives output:

at begin of main. creating std::vector<std::shared_ptr<void>> creating test test created leaving scope leaving main test destroyed 

i have ideas on why might work, have internals of std::shared_ptrs implemented g++. since these objects wrap internal pointer counter cast std::shared_ptr<test> std::shared_ptr<void> not hindering call of destructor. assumption correct?

and of course more important question: guaranteed work standard, or might further changes internals of std::shared_ptr, other implementations break code?

the trick std::shared_ptr performs type erasure. basically, when new shared_ptr created store internally deleter function (which can given argument constructor if not present defaults calling delete). when shared_ptr destroyed, calls stored function , call deleter.

a simple sketch of type erasure going on simplified std::function, , avoiding reference counting , other issues can seen here:

template <typename t> void delete_deleter( void * p ) {    delete static_cast<t*>(p); }  template <typename t> class my_unique_ptr {   std::function< void (void*) > deleter;   t * p;   template <typename u>   my_unique_ptr( u * p, std::function< void(void*) > deleter = &delete_deleter<u> )       : p(p), deleter(deleter)    {}   ~my_unique_ptr() {      deleter( p );      } };  int main() {    my_unique_ptr<void> p( new double ); // deleter == &delete_deleter<double> } // ~my_unique_ptr calls delete_deleter<double>(p) 

when shared_ptr copied (or default constructed) deleter passed around, when construct shared_ptr<t> shared_ptr<u> information on destructor call passed around in deleter.


Comments