有一个老技巧是给另一个函数有限的权限来创建一个对象;你传递一个令牌。
struct Example_shared_only {
private:
// permission token. explicit constructor ensures
// you have to name the type before you can create one,
// and only Example_shared_only members and friends can
// name it:
struct permission_token_t {
explicit permission_token_t(int) {}
};
public:
// public ctor that requires special permission:
Example_shared_only( permission_token_t ) {}
// delete special member functions:
Example_shared_only()=delete;
Example_shared_only(Example_shared_only const&)=delete;
Example_shared_only(Example_shared_only &&)=delete;
Example_shared_only& operator=(Example_shared_only const&)=delete;
Example_shared_only& operator=(Example_shared_only &&)=delete;
// factory function:
static std::shared_ptr<Example_shared_only>
make_shared() {
return std::make_shared<Example_shared_only>( permission_token_t(0) );
}
};
现在Example_shared_only::make_shared() 返回一个shared_ptr,它是用make_shared 创建的,没有其他人可以用它做很多事情。
如果您可以使用更现代的 C++ 方言,我们可以做得更好:
template<class F>
struct magic_factory {
F f;
operator std::invoke_result_t<F const&>() const { return f(); }
};
struct Example2 {
static std::shared_ptr<Example2> make() {
return std::make_shared<Example2>( magic_factory{ []{ return Example2{}; } } );
}
private:
Example2() = default;
};
Live example.
这需要c++17 保证省略。
magic_factory 可以转换为您的工厂函数生成的任何内容,并保证省略就地构建该对象。它在其他情况下有更好的用途,但在这里它允许您导出构造函数以进行共享。
传递给 magic_factory 的 lambda 是 Example2 的隐含朋友,这使其可以访问私有 ctor。保证省略意味着可以调用具有签名()->T 的函数来“就地”创建T,而无需任何逻辑副本。
make_shared<T> 尝试使用参数构造其T。发生这种情况时,C++ 会检查 operator T;我们的magic_factory 有一个这样的operator T。所以就用了。
它做了类似的事情
::new( (void*)ptr_to_storage ) Example2( magic_factory{ lambda_code } )
(如果您不熟悉,这称为“新放置”——它声明“请在ptr_to_storage 指向的位置构建一个Example2 对象)。
保证省略的美基本上传递到lambda_code,Example2 被创建的地址(又名ptr_to_storage),对象就在那里构造。