我有一个 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(),这似乎有很多样板文件。出现两个问题:
这是否比强制我类(class)的用户使用 try/catch 更简单?
有没有更简单的方法来实现我想要的:提供基本的异常保证并确保 close() 始终跟在 open() 之后?
最佳答案
嵌套类 opener
应该实现复制语义,因为如果我正确理解您的意图,编译器生成的默认代码会产生不良结果。
所以请实现复制构造函数和复制赋值。
或者,您可能希望通过声明1 private
来完全禁用复制语义,很像implementation of all standard stream classes .我更喜欢这种方法。
1。请注意,您不需要定义它们。只需在 private
部分声明它们就足够了。
关于C++ RAII 管理对象状态的改变和恢复,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7662789/