限定对象在堆上创建的需求
C++对象的一些使用场景其实已经有这种隐喻了,比如一个对象从std::enable_shared_from_this派生,当我们调用this->shared_from_this()的前提条件是这个对象已经被创建为shared_ptr,如果是一个栈对象去调用shared_from_this时会crash,所以使用派生于std::enable_shared_from_this的对象时,限定它只能在堆上创建可以保证代码的安全性。
struct dummy{
class token{
private:
token(){}
friend dummy;
};
static std::shared_ptr<dummy> create(){
return std::make_shared<dummy>(token{});
}
dummy(token) : dummy() {
}
private:
dummy(){}
};
int main() {
dummy d{}; //compile error
dummy d(token{}); //compile error
auto ptr = dummy::create(); //ok
}
这个代码借助了一个私有内部类token来避免在栈上创建dummy对象,因为外面无法访问这个token,只有它的友元类dummy才能访问token。另外一个问题是dummy的构造函数还是私有的,为什么这次改造之后可以用std::make_shared了?因为这里先通过public的dummy(token)去构造dummy对象的,然后dummy通过代理构造函数dummy()去真正构造一个dummy对象。
这个token在这里有两个作用,一个是用来避免在栈上构造dummy对象,一个是提供一个public的构造函数给std::make_shared使用。对于创建一个std::unique_ptr对象来说思路也是一样的,读者可以自行实现。至此,我们比较完美地实现了限定对象只能在堆上创建的目标。