Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
| From | "Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> |
|---|---|
| Newsgroups | comp.std.c++ |
| Subject | Re: make_shared and friends. |
| Date | 2012-05-02 11:11 -0700 |
| Organization | A noiseless patient Spider |
| Message-ID | <jnpp5s$n2g$1@dont-email.me> (permalink) |
| References | <5583145.28.1335476739188.JavaMail.geo-discussion-forums@ynnn35> <jnep30$d2s$1@dont-email.me> <17423064.271.1335555821298.JavaMail.geo-discussion-forums@vbq5> <jnj0aq$b2b$1@dont-email.me> <14621972.860.1335819954688.JavaMail.geo-discussion-forums@ynce8> |
On 01.05.2012 20:29, Jason McKesson wrote:
>
> On Sunday, April 29, 2012 11:59:51 PM UTC-7, Daniel Krügler wrote:
>>
>> Am 29.04.2012 02:02, schrieb Jason McKesson:
>> [..]
>>>
>>>
>>> It's not so much a problem as wondering how this is supposed to work.
>>> Without the ability to have `make_shared` be a friend (in a useful
>>> way), it is impossible to *force* users to use `make_shared`.
>>
>>
>>
>> I don't understand your question: Surely it cannot be the
>> responsibility of a library implementation to enforce user code to use
>> some particular component.
>
>
> A good API makes it difficult if not impossible to do things
> incorrectly. And if a particular object has `enable_shared_from_this`
> as a base class, then it is incorrect to create an instance of that
> object *without* a shared_ptr.
>
> So you have to either force the user to use `make_shared` or force the
> user to use factory functions. Enforcing either requires the use of
> private constructors.
No, happily[1] that's incorrect: as illustrated below, forcing the
user to use a factory function does not require access-restricted
constructors. We can just be a little smart about it. I described a
more convoluted technique for C++03 (which didn't support perfect
forwarding) in 2005 in section 1.3.5 of my "pointers tutorial"[2],
which for a while was linked to by Wikipedia's article on pointers.
However, regarding `make_shared` and `allocate_shared`, you're
apparently right that they can't be easily forced in any other way.
Their design is IMHO flawed by not supporting a deleter, and so we'll
just have to hope that functionality like shown below will appear in
some library Technical Report?
And then with similar optimization (namely, just one dynamic
allocation) recommended for create_shared as today with make_shared,
plus the important wording lacking for make_shared, enabling you to
be-friend the function or class that does the allocation.
Hopefully.
<code>
#include <memory>
#include <utility>
using namespace std;
//-------------------------------- Machinery:
template< class Type, class Deleter = std::default_delete<Type> >
class create_unique
: public unique_ptr< Type, Deleter >
{
public:
template< class... Args >
create_unique( Args&&... args )
: unique_ptr< Type, Deleter >(
new Type( forward<Args>( args )... ), Deleter()
)
{}
};
template< class Type, class Deleter = std::default_delete<Type> >
class create_shared
: public shared_ptr< Type >
{
public:
template< class... Args >
create_shared( Args&&... args )
: shared_ptr< Type >(
// Can very much be optimized by a std lib implementation:
new Type( forward<Args>( args )... ), Deleter()
)
{}
};
class WithProtectedSharedCreation
{
template< class Type, class Deleter > friend class create_shared;
protected:
static void* operator new( size_t const size )
{ return ::operator new( size ); }
static void* operator new( size_t const size, void* ) noexcept
{ return ::operator new( size ); }
static void operator delete( void* p )
{ ::operator delete( p ); }
static void operator delete( void* p, void* ) noexcept
{ ::operator delete( p ); }
};
//-------------------------------- Example usage:
class Blah
: public WithProtectedSharedCreation
, public enable_shared_from_this< Blah >
{
template< class Type> friend struct std::default_delete;
private:
Blah& operator=( Blah const& ) = delete;
protected:
Blah( Blah const& other ) = default;
virtual ~Blah(){} // Ensure dynamic allocation only.
Blah( double ) {} // Construction from `double` is protected.
public:
Blah() {}
Blah( int ) {}
Blah( char const* ) {}
};
int main()
{
//Blah o; &o; // !Nix.
//shared_ptr<Blah> pA( new Blah( "blah" ) ); // !Nyet.
//shared_ptr<Blah> pB = create_shared<Blah>( 3.14 ); // !Nah.
shared_ptr<Blah> p = create_shared<Blah>( "blah" );
shared_ptr<Blah> q = p->shared_from_this();
}
</code>
One advantage of the above is that the access levels of the
constructors then really say where they're available, as intended by
the language design.
E.g., the constructor taking a `double` above is protected, and
therefore can't be used via `create_shared` (you get a compilation
error).
Cheers & hth.,
- Alf
Notes:
[1] "Happily" because restricting access to the constructors is more
code, less clear code, less maintainable code, and in general it's
IMHO just very ugly and very kludgy; a spit, gum and rubber-string
solution.
[2] Google docs does not display the table of contents, but it's there
when the PDF is downloaded. <url:
https://docs.google.com/fileview?id=0B2oiI2reHOh4M2MzNzYwYzQtMGZkNC00NTljLWJiM2UtOGI0MmRkMTMyZGY4>
--
[ comp.std.c++ is moderated. To submit articles, try posting with your ]
[ newsreader. If that fails, use mailto:std-cpp-submit@vandevoorde.com ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Back to comp.std.c++ | Previous | Next — Previous in thread | Next in thread | Find similar
make_shared and friends. Jason McKesson <jmckesson@gmail.com> - 2012-04-27 11:12 -0700
Re: make_shared and friends. Daniel Krügler<daniel.kruegler@googlemail.com> - 2012-04-27 11:47 -0700
Re: make_shared and friends. Jason McKesson <jmckesson@gmail.com> - 2012-04-28 17:02 -0700
Re: make_shared and friends. Daniel Krügler <daniel.kruegler@googlemail.com> - 2012-04-29 23:59 -0700
Re: make_shared and friends. Jason McKesson <jmckesson@gmail.com> - 2012-05-01 11:29 -0700
Re: make_shared and friends. "Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> - 2012-05-02 11:11 -0700
Re: make_shared and friends. Daniel Krügler <daniel.kruegler@googlemail.com> - 2012-05-02 11:12 -0700
Re: make_shared and friends. "Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> - 2012-04-28 17:00 -0700
csiph-web