I have a certain design strategy where the constructor of my class is private and can only be constructed by friends of the class. Inside the friend function, I am trying to create a unique_pointer of my class using std::make_unique
but it doesn't compile. My VC12 compiler complains
c:\program files (x86)\microsoft visual studio 12.0\vc\include\memory(1639): error C2248: 'Spam::Spam' : cannot access private member declared in class 'Spam'
The relevant code which fails during compilation is as follows
#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);
}
Why am I not able to compile?
Here is another approach I've seen used, apparently known as the passkey idiom : have the public constructor require a private access token.
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);
}
In your case the function make_unique
is trying to create an instance of Spam
and that function is not a friend. Calling a non-friend function from inside a friend function does not imbue the non-friend function with friend status.
To solve this you can write in Foo
:
std::unique_ptr<Spam> spam(new Spam(10));
Why am I not able to compile?
You are unable to compile because make_unique
is not a friend of Spam
.
An alternative solution to making make_unique
a friend is to move the creation of the unique_ptr into Spam
.
class Spam {
...
private:
Spam(int) {}
static unique_ptr<Spam> create( int i )
{ return std::unique_ptr<Spam>( new Spam(i) ); }
};
and then have Foo
call that instead.
void Foo() {
std::unique_ptr<Spam> spam = Spam::create(10);
...
}
In your example, Foo()
is a friend
, but it isn't the function that's creating the Spam
- make_unique
is internally calling new Spam
itself. The simple fix is to just have Foo()
actually construct the Spam
directly:
void Foo() {
std::unique_ptr<Spam> spam(new Spam(10));
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With