【发布时间】:2011-10-05 14:20:14
【问题描述】:
我有一个班级 foo。对 foo 的操作需要调用 foo::open()、多个 foo::write(),并且必须以 foo::close() 调用结束:
#include <iostream>
class foo
{
public:
foo()
{
std::cout << "foo::foo()" << std::endl;
}
~foo()
{
std::cout << "foo::~foo()" << std::endl;
}
void open()
{
std::cout << "foo::open()" << std::endl;
}
void close()
{
std::cout << "foo::close()" << std::endl;
}
void write(const std::string& s)
{
std::cout << "foo::write(" << s << ")" << std::endl;
}
private:
// state that must be retained for entire lifetime of object
};
static void useFoo(foo& my_foo)
{
my_foo.open();
my_foo.write("string1");
my_foo.write("string2");
my_foo.close();
}
int main( int argc, char* argv[] )
{
foo my_foo;
useFoo(my_foo);
useFoo(my_foo);
}
正如预期的那样,这会输出以下内容:
foo::foo()
foo::open()
foo::write(string1)
foo::write(string2)
foo::close()
foo::open()
foo::write(string1)
foo::write(string2)
foo::close()
foo::~foo()
我想为我的类 foo 的用户提供一种方法,确保他们不会忘记调用 foo::close(),并确保在发生异常时调用 foo::close()。我不能使用 foo 的析构函数,因为 foo 必须在 foo::close() 之后继续存在,为下一个 foo::open() 做好准备。
我想出了这个 RAII 实现:
#include <iostream>
class foo
{
public:
class opener
{
public:
explicit opener(foo& my_foo):foo_(my_foo)
{
foo_.open();
};
~opener()
{
foo_.close();
};
private:
foo& foo_;
};
foo()
{
std::cout << "foo::foo()" << std::endl;
}
~foo()
{
std::cout << "foo::~foo()" << std::endl;
}
void open()
{
std::cout << "foo::open()" << std::endl;
}
void close()
{
std::cout << "foo::close()" << std::endl;
}
void write(const std::string& s)
{
std::cout << "foo::write(" << s << ")" << std::endl;
}
opener get_opener()
{
return(opener(*this));
}
private:
// state that must be retained for entire lifetime of object
};
static void useFoo(foo& my_foo)
{
foo::opener my_foo_opener = my_foo.get_opener();
my_foo.write("string1");
my_foo.write("string2");
}
int main( int argc, char* argv[] )
{
foo my_foo;
useFoo(my_foo);
useFoo(my_foo);
}
为简单起见,我没有包括让 foo::opener 类公开 foo::write() 方法的明显改进,尽管在真实对象中我会这样做以防止之前可能出现 write()一个打开()。
编辑 正如 Nawaz 在下面指出的那样,一个真正的类还需要一个复制构造函数和赋值运算符。
这似乎有很多样板,只是为了确保调用 close()。出现两个问题:
这还是比强制我的班级的用户使用 try/catch 更简单吗?
有没有更简单的方法来实现我想要的:提供基本的异常保证并确保 close() 始终遵循 open()?
【问题讨论】: