Подтвердить что ты не робот

Функция 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);
}

Почему я не могу скомпилировать?

4b9b3361

Ответ 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));
}