Функция Friend не может создать уникальный указатель класса
У меня есть определенная стратегия проектирования, где конструктор моего класса является приватным и может быть создан только друзьями класса. Внутри функции friend я пытаюсь создать уникальный_поинтер моего класса с помощью std::make_unique
, но он не компилируется. Мой компилятор VC12 жалуется
c:\program files (x86)\Microsoft Visual Studio 12.0\vc\include\memory (1639): ошибка C2248: "Спам:: Спам": не может получить доступ к закрытому члену, объявленному в классе "Спам"
Соответствующий код, который не выполняется во время компиляции, выглядит следующим образом
#include <memory>
class Spam {
public:
friend void Foo();
private:
Spam(int mem) :mem(mem) {}
int mem;
};
void Foo() {
std::unique_ptr<Spam> spam = std::make_unique<Spam>(10);
}
Почему я не могу скомпилировать?
Ответы
Ответ 1
В вашем случае функция make_unique
пытается создать экземпляр Spam
, и эта функция не является другом. Вызов функции, отличной от друга, из внутренней функции друга не влияет на функцию, отличную от друга, с состоянием друга.
Чтобы решить эту проблему, вы можете написать в Foo
:
std::unique_ptr<Spam> spam(new Spam(10));
Ответ 2
Вот еще один подход, который я видел: для публичного конструктора требуется токен частного доступа. Я не помню названия этого шаблона.
class Spam {
static struct Token {} const token;
friend void Foo();
public:
Spam(Token const&, int mem) :mem(mem) {}
private:
int mem;
};
void Foo() {
std::unique_ptr<Spam> spam = std::make_unique<Spam>(Spam::token, 10);
}
void Bar() {
// error: 'Spam::Token Spam::token' is private
// std::unique_ptr<Spam> spam = std::make_unique<Spam>(Spam::token, 10);
}
Ответ 3
Why am I not able to compile?
Вы не можете скомпилировать, потому что make_unique
не является другом Spam
.
Альтернативным решением для создания make_unique
друга является перемещение создания unique_ptr в Spam
.
class Spam {
...
private:
Spam(int) {}
static unique_ptr<Spam> create( int i )
{ return std::unique_ptr<Spam>( new Spam(i) ); }
};
а затем вместо этого наберите Foo
.
void Foo() {
std::unique_ptr<Spam> spam = Spam::create(10);
...
}
Ответ 4
В вашем примере Foo()
является friend
, но это не функция, создающая Spam
- make_unique
внутренне вызывающую new Spam
. Простое исправление состоит в том, чтобы просто Foo()
фактически построить Spam
напрямую:
void Foo() {
std::unique_ptr<Spam> spam(new Spam(10));
}