我有以下代码:
MyType x = do_something_dangerous();
// ...
if (some_condition) {
// ...
bar(x);
}
else {
// ...
}
// ...
if (another_condition_which_may_depend_on_previous_if_else} {
// ...
baz(x);
}
这个想法是,在某些情况下,提前确定可能很困难/不方便,我需要使用x
。但是在我不需要使用它的情况下,尝试初始化它可能是不好的(比如说,可能会导致我的进程崩溃)。
现在,似乎我需要使用的是initialize-on-demand holder(链接侧重于Java,所以这里是草图):某种Wrapper<MyType>
或{{1}使用Wrapper<MyType, do_something_dangerous>
方法,以便第一个get()
调用get()
和更晚do_something_dangerous()
只传递第一个调用获得的值。
备注:
get()
,但这会有点麻烦,也会扭曲预期用途:&#34;建议在只有一个明确的情况下使用boost::optional
(对于没有optional<T>
类型值的原因,以及缺乏价值与T
的常规值一样自然的原因。&#34; 答案 0 :(得分:5)
当然,如果你已经在你的应用程序中使用了boost,你可以查看建议的boost :: optional模块,但是我不确定它是否正是你想要的,因为它更适用于可为空的对象需要是推迟初始化。
我的建议是:坚持专用的包装器实现。
与其他答案不同,我认为你应该不使用单例,而只是像(使用初始化参数的实现):
template<typename T, typename I>
class LazyInit {
T* val;
I init;
public:
LazyInit<T, I>(I init): init(init) {
val = NULL;
}
~LazyInit<T, I>() {
delete val;
val = NULL; // normally useless here
}
T& get() {
if (val == NULL) {
val = new T(init);
}
return *val;
}
};
这是一个使用初始化函数的实现:
template<typename T>
class LazyInit {
T* val;
T (*init)();
public:
LazyInit<T>(T (*init)()): init(init) {
val = NULL;
}
~LazyInit<T>() {
delete val;
val = NULL; // normally useless here
}
T& get() {
if (val == NULL) {
val = new T(init());
}
return *val;
}
};
...
LazyInit<MyType> x(do_something);
...
bar(x.get()); // initialization done only here
您可以轻松地将两者结合起来,使用带参数的函数构建实现。
答案 1 :(得分:2)
如果你有c ++ 11,你可以使用std::async
和std::shared_future
的组合:
#include <iostream>
#include <future>
using namespace std;
struct LazyObj {
LazyObj() {
cout << "LazyObj init" << endl;
}
void test() {
cout << "LazyObj test" << endl;
}
};
int main() {
auto x = std::async(launch::deferred, []() -> LazyObj& {
static LazyObj a;
return a;
}).share();
int cond=0;
if( cond == 0 ) {
x.get().test();
x.get().test();
}
return 0;
}
在此用例launch::deferred
中std::async
不要创建执行线程,并在调用get()
时按需调用lambda。要允许多次调用get()
方法,我们会使用std::future
方法将std::shared_future
转换为share()
。现在我们可以在需要的时间或地点获得lazy-initialisaion对象。