c++ - 通过受保护的构造函数和静态成员函数强制使用 std::shared_ptr 以创建实例和 std::make_shared
问题描述
我有一些类只能通过std::shared_ptr
. 这些类的实例并非旨在通过在堆栈上分配它们或通过原始指针直接使用new
。我目前通过创建构造函数protected
并拥有一个static
实际执行对象实例化并将 a 返回shared_ptr
给对象的成员函数来强制执行此操作:
class Example {
protected:
Example() { }
public:
static std:shared_ptr<Example> create() { return std::shared_ptr<Example>(new Example()); }
};
我意识到这不是万无一失的,因为您仍然可以调用get()
,shared_ptr
但作为支持使用的指示似乎是合理的。
但是,我不能std::make_shared()
像构造函数那样使用protected
,而且我知道make_shared()
.
上述是不好的做法,还是有一种make_shared()
不使用构造函数的方法public
?
解决方案
有一个老技巧是给另一个函数有限的权限来制作一个对象;你传递一个令牌。
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;
};
这需要c++17来保证省略。
magic_factory
可以转换为您的工厂函数生成的任何内容,并保证省略就地构建该对象。它在其他上下文中具有更好的用途,但在这里它允许您导出构造函数以进行共享。
传递给的 lambdamagic_factory
是 的隐含友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 } )
(如果您不熟悉,这被称为“新放置”——它声明“请Example2
在 指向的位置构建一个对象ptr_to_storage
)。
保证省略的优点基本上传递到正在创建lambda_code
的地址(aka ),并且对象就在那里构造。Example2
ptr_to_storage
推荐阅读
- powershell - 在 Get-ADuser 上过滤时未定义 $env:USERNAME?
- postgresql - PostGIS 行作为十六进制 WKT 插入 Postgres
- android-room - 在房间数据库中嵌套观察者的任何替代方法?
- javascript - 控制台不显示数据
- colors - Meshlab 非分散顶点着色
- c++ - 如何在 C++20 中获得一个运行良好的生成器类模板?
- android - 颤振:未处理异常:断言失败:布尔表达式不能为空
- components - 这是哪个IC元件?
- javascript - 在数据表中添加 Excel 按钮时不显示页面长度
- c# - 如何将样式应用于 td 内的元素 - 使用 ItexSharp 将 html 转换为 PDF