дружественная функция std::make_shared() в Visual Studio 2010 (не Boost)

как сделать функцию друга std::make_shared().

Я пытался:

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

но это не работает (я использую Visual Studio 2010 SP1)


person uray    schedule 22.09.2011    source источник
comment
И под не работает мы подразумеваем...?   -  person Kerrek SB    schedule 23.09.2011
comment
Вызов std::make_shared‹T›() не может получить доступ к защищенному члену в T   -  person uray    schedule 23.09.2011
comment
Обратите внимание, что make_shared — это (вариативный) шаблон, и в любом случае, зачем ему быть другом? Ваш конструктор частный? Если да, то почему бы не использовать shared_from_this?   -  person Kerrek SB    schedule 23.09.2011
comment
Что вы пытаетесь сделать здесь? std::make_shared следует просто использовать - на самом деле вы не должны объявлять эту функцию, поскольку она уже существует как часть стандартной библиотеки. Вы пытаетесь вернуть общий указатель из своего собственного класса, используя специальный метод? В противном случае потребители вашего класса должны просто иметь возможность использовать std::make_shared в своем коде.   -  person Platinum Azure    schedule 23.09.2011
comment
возможный дубликат Могу ли я использовать boost::make_shared с частным конструктором ?   -  person Billy ONeal    schedule 23.09.2011
comment
@platinum: я делаю свой конструктор защищенным, так что мой класс может быть создан только как shared_ptr‹› (не необработанный указатель)   -  person uray    schedule 23.09.2011
comment
@kerrek: shared_from_this создает экземпляр класса? Насколько я знаю, это единственный перенос существующего экземпляра, который указан this как shared_ptr   -  person uray    schedule 23.09.2011
comment
@uray: это не так. На самом деле то, что делает make_shared, здесь не имеет никакого значения — для вызова конструктора вызывающий код должен иметь доступ к этому коду. Чаще всего это происходит с чем-то вроде make_shared (то есть с фабричным методом), но никакая реализация не может обойти этот тип контроля доступа и при этом иметь четко определенное поведение.   -  person Billy ONeal    schedule 23.09.2011
comment
@uray: Ты прав, неважно.   -  person Kerrek SB    schedule 23.09.2011
comment
Хм, я нашел специфичное для реализации решение для GCC. Проблема в том, что make_shared на самом деле вызывает не конструктор, а какой-то другой внутренний класс.   -  person Kerrek SB    schedule 23.09.2011
comment
@Kerrek: да, в моем случае это класс счетчика ссылок shared_ptr, который вызывает конструктор.   -  person uray    schedule 23.09.2011


Ответы (4)


Как насчет добавления статического метода в ваш класс:

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

Вот небольшой лайфхак:

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

Никто не может использовать общедоступный конструктор, кроме самого класса. По сути, это неинтерфейсная часть общедоступного интерфейса. Спросите у Java-людей, есть ли у такой штуки имя :-)

person Kerrek SB    schedule 22.09.2011
comment
это то, что я на самом деле делаю, но этот std::make_shared<Foo>() не может получить доступ к моему конструктору, который находится в частном порядке Foo - person uray; 23.09.2011
comment
Обновлено (я думаю, только) портативным решением. - person Kerrek SB; 23.09.2011
comment
ваш ответ правильный, я тоже так делал, но мой вопрос больше о том, как использовать std::make_shared<>, чем new - person uray; 23.09.2011
comment
@uray: почему ты так часто используешь std::make_shared<>() вместо std::shared_ptr<>(new)? - person Griwes; 23.09.2011
comment
@Griwes: это более эффективно. - person Puppy; 23.09.2011
comment
@uray: я считаю, что вы не можете использовать make_shared в этой ситуации. make_shared предъявляет определенные требования, и доступный конструктор, похоже, является одним из них. Вы могли бы взломать это, возможно, создав открытый конструктор, который зависит от частного класса. Позвольте мне отредактировать это. - person Kerrek SB; 23.09.2011
comment
@DeadMG: ладно, тогда — просто из любопытства — чем именно make_shared отличается от shared_ptr(new)? - person Griwes; 23.09.2011
comment
@griwes: потому что я просто хочу, просто любопытно, и stackoverflow.com /вопросы/7044168/ - person uray; 23.09.2011
comment
@Griwes: make_shared создает версию shared_ptr, которая использует только одно динамическое выделение, а не два для всех остальных версий. Обратите внимание, что make_shared не принимает ни аргументы удаления, ни аргументы распределителя; это ограничение гибкости покупает вам эффективность. - person Kerrek SB; 23.09.2011
comment
@Kerrek: Ну, вы можете использовать allocate_shared, если вам нужен собственный распределитель. - person ; 23.09.2011
comment
@Mike: Хороший звонок, я думал, что должно быть что-то подобное! :-) - person Kerrek SB; 23.09.2011
comment
Статическая функция-член create должна называться make_shared. - person curiousguy; 10.10.2011

Это не работает, потому что реализация VC10 передает построение внутренней вспомогательной функции. Вы можете копаться в исходном коде и добавлять эту функцию в друзья, если хотите.

person Puppy    schedule 22.09.2011
comment
То же самое с GCC, где вам нужно подружиться с std::_Sp_counted_ptr_inplace. - person Kerrek SB; 23.09.2011
comment
Это сработало для меня в VS2015, добавив friend std::_Ref_count_obj<Foo>;. - person Emilian Cioca; 24.08.2015

Если вы не против вникать в детали внутренней реализации используемого вами компилятора, для VC10/Visual C++ 2010, как уже упоминал @DeadMG, вы можете подружиться с внутренней реализацией. Вы захотите подружиться с std::tr1::_Ref_count_obj<T>.

Я тестировал это с помощью оптимизирующего компилятора Microsoft (R) C/C++ версии 16.00.40219.01 для x64.

person chwarr    schedule 17.05.2013

Класс, к внутренним данным которого вы хотите получить доступ, должен объявлять другие классы друзьями, поскольку это нарушает стандартную инкапсуляцию.

Вы не можете сделать так, чтобы std::make_shared сделал ваш класс другом, и если вы не меняете std::make_shared, он не должен хотеть, чтобы ваш класс был другом.

Итак, если я неправильно понимаю вопрос - то, что вы просите, не может быть сделано.

person John Humphreys    schedule 22.09.2011