Opened 14 years ago
Closed 9 years ago
#2481 closed Feature Requests (fixed)
make_shared and allocate_shared friendship
Reported by: | Owned by: | Peter Dimov | |
---|---|---|---|
Milestone: | To Be Determined | Component: | smart_ptr |
Version: | Boost 1.36.0 | Severity: | Problem |
Keywords: | Cc: | jwakely.boost@… |
Description
It is currently vary difficult to have a class with private constructors use make_shared and allocate_shared. This same classes are some ideal candidates for private constructors because any class that derives from enable_shared_from_this should probably have private constructors to prevent misuse. Simplifying friend declarations for these functions would be very helpful.
For example:
class Foo : public enable_shared_from_this<Foo> { friend class make_shared_access; Foo(); }; int main() { shared_ptr<Foo> foo( make_shared<Foo>() ); }
Attachments (1)
Change History (10)
by , 14 years ago
Attachment: | make_shared_access.patch added |
---|
comment:1 by , 14 years ago
comment:2 by , 14 years ago
One limitation of your solution: suppose I have private constructors and a static factory function for a class, and the factory function returns a shared_ptr. If I make make_shared_access a friend, it opens a hole where people can still create objects of the class without using the factory function by using make_shared or allocate_shared directly.
comment:3 by , 14 years ago
Cc: | added |
---|
Right, you don't even need the make_shared_access extension to open that hole, the design is compromised if you declare make_shared or allocate_shared as a friend.
Given:
class MustUseFactory { MustUseFactory() { } public: static shared_ptr<MustUseFactory> create(); };
You can still use make_shared by using aliasing:
shared_ptr<MustUseFactory> MustUseFactory::create() { typedef aligned_storage<sizeof(MustUseFactory)> Storage; shared_ptr<Storage> storage = make_shared<Storage>(); MustUseFactory* p = new (storage->address()) MustUseFactory(); return shared_ptr<MustUseFactory>(storage, p); }
This doesn't work with enable_shared_from_this, I leave that as an exercise for the reader ;-)
comment:4 by , 14 years ago
Milestone: | Boost 1.38.0 → Boost 1.39.0 |
---|---|
Status: | new → assigned |
comment:5 by , 14 years ago
It still seems to me that the best course of action is to make allocate_shared use A::construct. Unfortunately, this doesn't work with C++03 allocators, whose construct method only takes a single T const& argument. C++0x allocators are OK, but changing boost::allocate_shared to call construct will make it fail for C++03 allocators.
comment:6 by , 13 years ago
Milestone: | Boost 1.39.0 → To Be Determined |
---|
comment:7 by , 12 years ago
Status: | assigned → new |
---|
comment:8 by , 11 years ago
Using std::allocator_traits<A>::construct will work with C++11 or C++03 allocators, which is what LWG 2070 suggests and what I've implemented for GCC 4.7
Of course that requires a C++11 library that provides allocator_traits
comment:9 by , 9 years ago
Resolution: | → fixed |
---|---|
Status: | new → closed |
boost::allocate_shared now uses std::allocator_traits<>::construct and destroy (if available), as per LWG 2070.
Added a brute force patch that implements this for c++03 against boost 1.36 release. I left variadic template support as a todo because I don't know the syntax and don't have a compiler for it.