带有 std::make_shared 的密码习语。 xmemory 无法访问私钥构造函数

Passkey idiom with std::make_shared. xmemory cannot access private Key constructor

在我的程序中,我需要一个提供单独 class 实例的工厂函数,因为我需要控制每个实例的细节,并了解一次存在多少个实例。特别是返回 std::shared_ptr 是理想的,但由于 std::pointer 类型的“make”函数的已知问题,这最初是不可能的,因为它们需要与我的 Widget [=36= 成为朋友] 也是不可移植的,因为它依赖于那些可能会改变的方法的当前实现。

为了解决这个问题,我想使用 Passkey 习惯用法,它是针对这种情况直接推荐的,如本文底部所述:https://abseil.io/tips/134. I also based my implementation off the lessons learned here: 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 实例的构造发生在属于 Factory 的 factoryMake() 函数中,然后该实例被传递给 std::make_shared 函数;因此,std::make_shared 不需要访问 Key 构造函数,因为一个已经构造好的实例被传递给它,这就是在这种情况下使用这个习语的全部意义所在。 class 本身是 public 因此它与 Key 类型交互应该没有问题,只有构造函数应该是不可访问的。

最后我可以跳过使用 std::make_shared 而是使用带有原始指针的 shared_ptr(*T) 构造函数,但是由于它需要额外的分配,所以效率稍低,正如我在第一个 link 中指出的那样。这没什么大不了的,因为我没有制作很多小部件,但我最终更愿意让更理想的实现工作。

我在这里错过了什么?

问题是当你调用std::make_shared时,编译器需要复制你的Widget::Key,而你已经将复制构造函数声明为private。您可以通过以下两种方式之一解决此问题:

  1. 创建Widget::Key的拷贝构造函数public.

  2. 更改 Widget 构造函数以通过 const 引用获取 Widget::Key

    explicit Widget(const Key&, ...