6

how to make friend function of std::make_shared().

I tried:

class MyClass{
public:
     friend std::shared_ptr<MyClass> std::make_shared<MyClass>();
     //or
     //friend std::shared_ptr<MyClass> std::make_shared();
protected:
     MyClass();
};

but it does not work (i'am using Visual Studio 2010 SP1)

rwong
  • 6,062
  • 1
  • 23
  • 51
uray
  • 11,254
  • 13
  • 54
  • 74
  • And by "doesn't work" we mean...? – Kerrek SB Sep 22 '11 at 21:26
  • std::make_shared() invocation cannot access protected member in T – uray Sep 22 '11 at 21:27
  • 1
    Note that `make_shared` is a (variadic) template, and in any case, why does it need to be a friend? Is your constructor private? If so, why not use `shared_from_this`? – Kerrek SB Sep 22 '11 at 21:27
  • What are you trying to do here? `std::make_shared` should just be used-- you aren't actually supposed to declare that function since it already exists as part of the standard library. Are you trying to return a shared pointer from your own class using a special method? Otherwise, consumers of your class should just be able to use `std::make_shared` in their code. – Platinum Azure Sep 22 '11 at 21:28
  • 1
    possible duplicate of [Can I use boost::make_shared with a private constructor?](http://stackoverflow.com/questions/2590310/can-i-use-boostmake-shared-with-a-private-constructor) – Billy ONeal Sep 22 '11 at 21:28
  • @platinum: i make my constructor protected, so that my class can only be instantiated as shared_ptr<> (not raw pointer) – uray Sep 22 '11 at 21:33
  • @kerrek: does `shared_from_this` instantiate class? AFAIK, its only wrap existing instance which pointed by `this` as `shared_ptr` – uray Sep 22 '11 at 21:35
  • 1
    @uray: It isn't. Really, what make_shared is doing has no effect here -- to call the constructor the calling code needs to have access to that code. It's most common with something like `make_shared` (i.e. a factory method) -- but no implementation can work around this kind of access control and still have well defined behavior. – Billy ONeal Sep 22 '11 at 21:35
  • @uray: You're right, never mind that. – Kerrek SB Sep 22 '11 at 21:37
  • Hm, I found an implementation-specific solution for GCC. The problem is that `make_shared` isn't actually calling the constructor, but some other, internal class is. – Kerrek SB Sep 22 '11 at 21:59
  • @Kerrek: yup, in my case, its the reference counter class of `shared_ptr` who call the constructor. – uray Sep 22 '11 at 22:01

4 Answers4

14

How about adding a static method to your class:

class Foo
{
public:
  static shared_ptr<Foo> create() { return std::shared_ptr<Foo>(new Foo); }
private:
  // ...
};

Here's a little hackaround:

class Foo
{
  struct HideMe { };
  Foo() { };
public:
  explicit Foo(HideMe) { };
  static shared_ptr<Foo> create() { return std::make_shared<Foo>(HideMe());
};

Nobody can use the public constructor other than the class itself. It's essentially a non-interface part of the public interface. Ask the Java people if such a thing has a name :-)

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • this is what actually I'am doing, but that `std::make_shared()` can't access my constructor which is in private of `Foo` – uray Sep 22 '11 at 21:41
  • Updated with the (I believe only) portable solution. – Kerrek SB Sep 22 '11 at 22:00
  • your answer is correct, I did it too, but my question is more to how to use `std::make_shared<>` than `new` – uray Sep 22 '11 at 22:03
  • @uray: why do you want to use `std::make_shared<>()` so much, instead of `std::shared_ptr<>(new)`? – Griwes Sep 22 '11 at 22:06
  • 1
    @Griwes: It's more efficient. – Puppy Sep 22 '11 at 22:07
  • 2
    @uray: I believe you cannot use `make_shared` in this situation. `make_shared` has certain requirements, and an accessible constructor seems to be one of them. You could hack around that perhaps by making a public constructor that depends on a private class. Let me edit that. – Kerrek SB Sep 22 '11 at 22:07
  • @DeadMG: ok, then - just out of curiosity - what exactly does the `make_shared` do differently from `shared_ptr(new)`? – Griwes Sep 22 '11 at 22:09
  • @griwes : because I just want to, just curious, and http://stackoverflow.com/questions/7044168/question-about-boostmake-shared – uray Sep 22 '11 at 22:09
  • 2
    @Griwes: `make_shared` creates a version of `shared_ptr` that only uses one dynamic allocation, as opposed to two for all the other versions. Note that `make_shared` accepts neither deleter nor allocator arguments; this limitation of flexibility buys you efficiency. – Kerrek SB Sep 22 '11 at 22:11
  • 1
    @Kerrek: Well you can use `allocate_shared` if you want a custom allocator. –  Sep 23 '11 at 00:48
  • @Mike: Good call, I thought there should be something like that! :-) – Kerrek SB Sep 23 '11 at 00:52
  • The `create` static member function should be named `make_shared`. – curiousguy Oct 10 '11 at 13:23
4

It doesn't work because the VC10 implementation hands off construction to an internal helper function. You can dig through the source code and friend this function if you want.

Puppy
  • 144,682
  • 38
  • 256
  • 465
1

If you are okay with delving into the internal implementation details of the compiler that you are using, for VC10/Visual C++ 2010, as @DeadMG mentioned, you can befriend the internal implementation. You'll want to befriend std::tr1::_Ref_count_obj<T>.

I've tested this with Microsoft (R) C/C++ Optimizing Compiler Version 16.00.40219.01 for x64

chwarr
  • 6,777
  • 1
  • 30
  • 57
0

The class who's internal data you want access to is the one that has to declare other classes as friends as it breaks standard encapsulation.

You cant have std::make_shared make your class a friend, and assuming you're not changing std::make_shared, it shouldn't want your class to be a friend.

So, unless I understand the question wrong - what you're asking can't be done.

John Humphreys
  • 37,047
  • 37
  • 155
  • 255