Friend函数无法构造类的唯一指针

问题描述 投票:13回答:4

我有一个特定的设计策略,我的类的构造函数是私有的,只能由类的朋友构建。在友元函数内部,我正在尝试使用std::make_uniquebut创建我的类的unique_pointer,它不能编译。我的VC12编译器抱怨

c:\ program files(x86)\ microsoft visual studio 12.0 \ vc \ include \ memory(1639):错误C2248:'Spam :: Spam':无法访问类'Spam'中声明的私有成员

编译过程中失败的相关代码如下

#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);
}

为什么我无法编译?

c++ c++11 friend unique-ptr
4个回答
17
投票

在你的情况下,函数make_unique试图创建一个Spam的实例,该函数不是朋友。从朋友函数内部调用非朋友函数不会使非朋友函数充满朋友状态。

要解决这个问题,你可以写Foo

std::unique_ptr<Spam> spam(new Spam(10));

17
投票

这是我见过的另一种方法,显然称为密码习语:公共构造函数需要私有访问令牌。

class Spam {
    struct Token {};
    friend void Foo();
public:
    Spam(Token, 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);
}

5
投票
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);
    ...
}

1
投票

在你的例子中,Foo()是一个friend,但它不是创建Spam的函数 - make_unique在内部调用new Spam本身。简单的解决方法就是让Foo()直接构建Spam

void Foo() {
    std::unique_ptr<Spam> spam(new Spam(10));
}
© www.soinside.com 2019 - 2024. All rights reserved.