Идиома ключа доступа с std :: make_shared. xmemory не может получить доступ к конструктору закрытого ключа - PullRequest
0 голосов
/ 01 августа 2020

В моей программе мне нужна фабричная функция, которая предоставляет экземпляры отдельного класса, потому что мне нужно контролировать детали каждого экземпляра и знать, сколько экземпляров существует одновременно. В частности, возвращение std :: shared_ptr является идеальным, но изначально это невозможно из-за известной проблемы с функциями "make" для типов std :: pointer, поскольку они также должны были бы дружить с моим классом Widget, который не является не переносится, так как он полагается на текущую реализацию тех методов, которые могут измениться.

Чтобы обойти это, я хочу использовать идиому Passkey, которая была напрямую рекомендована для этой ситуации, как описано в нижней части этого : https://abseil.io/tips/134. Я также основывал свою реализацию на уроках, извлеченных здесь: https://arne-mertz.de/2016/10/passkey-idiom/

Это пример проекта, в котором используются те же настройки, что и в моем полном проекте:

#include <iostream>

class Widget
{
public:
    class Key
    {
        friend class Factory;
    private:
        Key() {};
        Key(const Key&) = default;
    };

    int mTest;

    explicit Widget(Key, int test) { mTest = test; }

    int getTestVar() { return mTest; }
};

class Factory
{
public:

    int mTestPass;

    Factory(int input) { mTestPass = input; }

    std::shared_ptr<Widget> factoryMake() { return std::make_shared<Widget>(Widget::Key{}, mTestPass); }
};

int main()
{
    Factory testFactory(10);
    std::shared_ptr<Widget> testWidget = testFactory.factoryMake();

    std::cout << testWidget->getTestVar();

    return 0;
}

Однако я получаю

Error   C2248   'Widget::Key::Key': cannot access private member declared in class 'Widget::Key'    TestProject ...\include\xmemory 204 

Это меня полностью потеряло, поскольку ошибка исходит из xmemory. cpp указывает, что std :: make_shared все еще пытается получить доступ к частному конструктору. Насколько мне известно, создание экземпляра Key происходит внутри функции factoryMake (), которая принадлежит Factory, а затем этот экземпляр передается в функцию std :: make_shared; следовательно, std :: make_shared не должен нуждаться в доступе к конструктору Key, поскольку ему передается уже созданный экземпляр, что и составляет весь смысл использования этой идиомы в данном контексте. Сам класс publi c, поэтому у него не должно возникнуть проблем с взаимодействием с типом Key, только конструктор должен быть недоступен.

В конце я могу просто пропустить использование std :: make_shared и вместо этого использовать shared_ptr (* T) конструктор с необработанным указателем, но он немного менее эффективен из-за того, что он требует дополнительного выделения, как отмечалось в моей первой ссылке. Это не имеет большого значения, поскольку я не делаю много виджетов, но в конечном итоге я бы предпочел, чтобы работала более идеальная реализация.

Что мне здесь не хватает?

1 Ответ

1 голос
/ 01 августа 2020

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

  1. Сделайте конструктор копирования Widget::Key publi c.

  2. Измените Widget конструктор, который принимает Widget::Key по ссылке const:

    explicit Widget(const Key&, ...

...