f



Restricting a class to dynamic instantiation via destructor access -- what about smart pointers?

For a restriction to dynamic allocation by making the destructor 
non-`public`, I wonder what would be a good way to support destructor 
invocation via `std::shared_ptr` and other smart pointers?

[code]
#include <type_traits>
#include <iostream>
using namespace std;

#define STATIC_ASSERT( e ) static_assert( e, "`" #e "` <-- must be true" )

namespace cppx{
     template< class Type >
     constexpr auto is_destructible()
         -> bool
     { return std::is_destructible<Type>::value; }
}  // namespace cppx

template< class Derived >
struct Dynamic_only
{
     void selfdestroy() { delete this; }

     virtual ~Dynamic_only() {}

     Dynamic_only()
     {
         using cppx::is_destructible;
         STATIC_ASSERT( not is_destructible<Derived>() );
     }
};

struct S: Dynamic_only<S> {};
class T: public Dynamic_only<T> { private: ~T(){} };
class U: public Dynamic_only<U>{ protected: ~U(){} };

auto main() -> int
{
#ifdef TEST_INSTANTIATION
     new S{};
     new T{};
     new U{};
#endif
     cout << boolalpha;
     cout << "S -> " << is_destructible<S>::value << "\n";   // true
     cout << "T -> " << is_destructible<T>::value << "\n";   // false
     cout << "U -> " << is_destructible<U>::value << "\n";   // false
}
[/code]


Cheers!,

- Alf
0
Alf
12/24/2016 3:00:31 AM
comp.lang.c++ 49423 articles. 5 followers. Post Follow

2 Replies
327 Views

Similar Articles

[PageSpeed] 54

"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> writes:
>For a restriction to dynamic allocation by making the destructor 
>non-`public`, I wonder what would be a good way to support destructor 
>invocation via `std::shared_ptr` and other smart pointers?

  My quick take at it; I am not restricting the access
  to the destructor, but to the constructor.

#include <iostream>
#include <new>
#include <memory>

class dynamic_only
{ int x_;
  explicit dynamic_only( int const x ): x_{ x } {}

  public:

  int x() const { return x_; }

  template< typename... Args >
  static ::dynamic_only * make_new( Args && ... args )
  { return new ::dynamic_only( ::std::forward< Args >( args )... ); }

  template< typename... Args >
  static ::std::unique_ptr< dynamic_only >
  make_unique( Args && ... args )
  { return ::std::unique_ptr< dynamic_only >
    ( new ::dynamic_only( ::std::forward< Args >( args )... )); }};

int main()
{ // ::dynamic_only d( 2 ); // error: 'dynamic_only( int )' is private
  ::dynamic_only * const do0 = ::dynamic_only::make_new( 2 );
  ::std::unique_ptr< ::dynamic_only > do1 = ::dynamic_only::make_unique( 2 );
  ::std::clog << do0->x() << '\n';
  ::std::clog << do1->x() << '\n';
  ::delete( do0 ); /* do0 is not managed exception-safely here */ }


0
ram
12/24/2016 4:10:34 AM
ram@zedat.fu-berlin.de (Stefan Ram) writes:
>My quick take at it; I am not restricting the access
>to the destructor, but to the constructor.

  A slightly modified version:

#include <iostream>
#include <new>
#include <memory>

template< class T >
struct dynamic_only_support
{
  template< typename... Args >
  static T * make_new( Args && ... args )
  { return new T( ::std::forward< Args >( args )... ); }

  template< typename... Args >
  static ::std::unique_ptr< T >
  make_unique( Args && ... args )
  { return ::std::unique_ptr< T >
    ( new T( ::std::forward< Args >( args )... )); } };

class dynamic_only : public dynamic_only_support < dynamic_only >
{ friend struct dynamic_only_support < dynamic_only >;

  int x_;
  explicit dynamic_only( int const x ): x_{ x } {}

  public:
  int x() const { return x_; }};

int main()
{ /* ::dynamic_only d;      */ /* error */
  /* ::dynamic_only d( 2 ); */ /* error */
  auto const dp0 = ::dynamic_only::make_unique( 2 );
  auto const dp1 = ::dynamic_only::make_new( 2 );
  ::std::clog << dp0->x() << '\n';
  ::std::clog << dp1->x() << '\n';
  ::delete( dp1 ); /* dp1 is not managed exception-safely here */ }


0
ram
12/24/2016 10:55:21 PM
Reply: