【发布时间】:2015-01-25 23:38:06
【问题描述】:
考虑这个类:
class Widget
{
Widget::Widget();
bool initialize();
}
一个Widget具有以下特点:
-
必须调用
initialize()才能完全构造 -
initialize()可能会失败 -
initialize()很贵
鉴于此,我将创建封装在始终返回相同 Widget 实例的工厂函数中:
Widget* widget() {
static auto w = new Widget;
static auto initialized = false;
if (!initialized) {
if (!w->initialize()) {
return nullptr;
}
initialized = true;
}
return w;
}
widget() 的返回类型应该是什么?
特别是,我想以某种方式明确返回的Widget 的生命周期将超过任何调用者,但不引用内部实现。
- 返回一个原始指针并添加一条注释,指出“返回的指针指向一个具有静态存储持续时间的对象,在程序结束前不会被删除”。这很简单,但不是自我记录。
- 返回
std::shared_ptr<Widget>。这是自记录的,但我不喜欢它会引入完全不必要的引用计数开销。 - 返回一个
std::unique_ptr<Widget>,其中包含一个自定义删除器函数,该函数是无操作的。如果调用者将其转换为shared_ptr,我认为这与#2 具有相同的感知问题。
【问题讨论】:
-
这确实是一个见仁见智的问题,但在这种特殊情况下,我不会担心重新计算开销。如果您的 Widget 类型的创建“成本很高”,那么相比之下,任何“不必要的引用计数开销”都可能是微不足道的。
-
我们应该忽略这个的多线程不安全性吗? (即使在 C++11 中这也不安全)
-
我不认为工厂是这个的正确术语。在我看来,工厂是创建对象并将所有权传递给调用者的东西。这更像是一个单例。
-
我认为 2. 和 3. 根本不是自我记录。如果我调用返回
std::shared_ptr/std::unique_ptr的函数,我希望获得共享/唯一所有权。 -
@JoshuaJohnson 假设 C++11:虽然静态变量的初始化保证是线程安全的(运行时有责任确保静态初始化只发生一次),但检查 @987654335 的代码@ 不安全。如果
widget()函数几乎同时在两个线程中被调用,则两个线程都可能认为initialized仍然为假,并且它们都将调用initialize()。特别是如果initialize()make 需要一些时间,这会增加双重初始化的可能性。
标签: c++ c++11 factory smart-pointers lifetime