好还是坏 C++ 习语 - 纯粹用于构造函数/析构函数的对象?
我有一些类,除了它们的构造函数/析构函数之外什么都不做。 这是一个
class BusyCursor
{
private:
Cursor oldCursor_;
public:
BusyCursor()
{
oldCursor_ = CurrentCursor();
SetCursor(BUSY_CURSOR);
}
~BusyCursor()
{
SetCursor(oldCursor_);
}
}
// example of use
void DoSlowThing
{
BusyCursor busy;
... do something time-consuming ...
}
我有点担心未来可读性的例子。 我在这里是否太“狡猾”了,使用了一个从未在代码中实际使用过的变量(“忙”)? 某些静态分析工具是否会建议将它们删除,或者这种习惯用法是否足够普遍而不必担心?
I have a few classes which do nothing except in their constructors/destructors. Here's an example
class BusyCursor
{
private:
Cursor oldCursor_;
public:
BusyCursor()
{
oldCursor_ = CurrentCursor();
SetCursor(BUSY_CURSOR);
}
~BusyCursor()
{
SetCursor(oldCursor_);
}
}
// example of use
void DoSlowThing
{
BusyCursor busy;
... do something time-consuming ...
}
I'm a little concerned about future readability. Am I being too "tricksy" here, with a variable ("busy") which is never actually used in the code? Could some static analysis tool suggest they be removed, or is this idiom sufficiently common not to worry about?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
这种技术非常常见,被称为设计模式:资源获取即初始化 (RAII) 。
我会毫不犹豫地使用这种设计模式。
最好使用这种设计模式进行编码,因为您可以避免由于忘记重置光标或任何有问题的资源而出现错误。
如果您担心其他程序员可能无法理解它,那么这些程序员应该受过更多教育。 始终努力以最无错误的方式编码,这样你和其他人就不可能搬起石头砸自己的脚。
“一些静态分析工具是否会建议将它们删除?”
原因是因为创建了对象并调用了构造函数/析构函数。 所以它不是一个未引用的变量。
This technique is very common and is known as the design pattern: Resource Acquisition Is Initialization (RAII).
I would not hesitate to use this design pattern at all.
It's much better that you are coding using this design pattern because you will avoid bugs by forgetting to reset the cursor, or whatever the resource in question is.
If you are concerned that other programmers might not understand it, then those programmers should be more educated. Always strive to code in the most error free way where you make it impossible for you and others to shoot yourself/themselves in the foot.
"Could some static analysis tool suggest they be removed?"
The reason is because the object is created and the constructor/destructor are called. So it is not an unreferenced variable.
正如其他人所说,这是很好的 C++ 风格。 为了提高可读性,我总是在此类仅限 RAII 的类前面加上
Scoped
前缀(例如ScopedBusyCursor
),以便一目了然地清楚该类的用途。As others have said, this is good C++ style. To aid readability, I always prefix such RAII-only classes with
Scoped
(for example,ScopedBusyCursor
) to make it clear from a glance what the class's purpose is.这是一个众所周知且良好的 C++ 习惯用法,就像其他人的回答一样。
为了明确这些类只能在一个范围内使用,而不能在不同范围之间移动,最好将它们设置为不可复制。 这可以通过添加未实现的私有复制构造函数和复制赋值运算符来手动完成。 更短、更易读的方法是从 派生类boost::不可复制:
This a well-known and good C++ idiom, like the others answered.
To make it clear that the classes are meant to be only used within a scope and not to be moved between different scopes, it might be good to make them noncopyable. This can be done manually by adding an unimplemented private copy-constructor and copy-assignment operator. The shorter and more readable way is to derive the class from boost::noncopyable:
这是一个很好的习语,也很常用。
它比任何替代方案都要好,例如,即使您的一些耗时的代码抛出异常,
~BusyCursor
析构函数仍然会被调用。It's a good idiom and commonly used.
It's better than any alternative, for example even if your something time-consuming code throws an exception, the
~BusyCursor
destructor will still be called.可以说,不使用这种模式是不好的习惯用法。 当您不使用 RAII 时,您的代码最终看起来像这样:
您真的认为在整个代码中散布这些代码更有利于维护吗?
Arguably not using this pattern is the bad idiom. When you are not using RAII your code ends up looking like this:
Do you really think having that littered throughout your code is better for maintenance?
没有健全的静态分析工具会建议删除该变量,因为它已被使用。 它之所以有效,是因为调用了它的构造函数和析构函数。 你应该绝对安全。
No sane static analysis tool would suggest removing the variable, becaues it is used. It has an effect because its constructor and destructor are called. You should be perfectly safe.
其他人已经提到这是经典的 RAII。
我要补充的是,这是 C++ 最好的事情之一。 很少有其他语言支持它,或者至少正确支持它(即使 C# 的 using 构造也不是那么好,因为负担仍然在客户端代码上 - 请参阅我的博客文章)。
它与 C++ 的联系如此紧密,以至于您应该相信任何阅读它的人都会熟悉它 - 即使不是,他们也应该熟悉它。
Others have already mentioned that this is classic RAII.
What I'll add is to say that this is one of the best things about C++. Very few other languages support it, or at least support it properly (even C#'s using construct isn't as good, as the burden is still on the client code - see my blog entry on this).
It's become so closely associated with C++ that you should feel confident that anyone reading it would be familiar with it - and if not they should be.
我通常称其为“守卫”。 在我看来,它展示了 C++ 最大的优势之一(确定性资源处理)。 这是我在使用垃圾收集语言时最怀念的事情之一。
I usually refer to this as a "guard". In my opinion it demonstrates one of C++'s biggest strengths (deterministic resource-handling). It's one of the things I miss the most when working in garbage-collected languages.
您还可以使用 Andrei Alexandrescu 和 Petru Marginean 的 ScopeGuard 之类的东西。 那么您的示例将如下所示:
这使得执行一次性 RAII 类型操作变得更容易,而无需为每个操作创建一个新类。 然而,对于您的 Cursor 示例,由于它是一个您可能会多次重复使用的类,因此您可能最好使用专用类。
You can also go with something like ScopeGuard by Andrei Alexandrescu and Petru Marginean. Your sample would look something like this then:
This makes it easier to do one-off RAII-type operations without having to create a new class for each one. However for your Cursor example, since it's a class you'll likely reuse many times, you're probably better off with the dedicated class.