关于习语:C ++中的“哨兵对象”是什么?

What is “sentry object” in C++?

我回答了这个问题,而布托斯瓦特也回答了

The modern C++ equivalent would be a
sentry object: construct it at the
beginning of a function, with its
constructor implementing call(), and
upon return (or abnormal exit), its
destructor implements

我不熟悉在C++中使用哨兵对象。我认为它们仅限于输入和输出流。

有人可以向我解释C++的StEnter对象以及如何将它们作为类中的一个或多个方法的截取器来使用吗?

也就是说,如何做到这一点?

Sentry objects are very similar
indeed. On the one hand they require
explicit instantiation (and being
passed this) but on the other hand you
can add to them so that they check not
only the invariants of the class but
some pre/post conditions for the
function at hand.


哨兵的目标是一种模式,但我不确定下面哪一个(也许全部)。

当一个对象(可能是用户定义的类)被破坏时,即当它的析构函数被调用时,C++程序常常严重依赖于知识。对于使用垃圾收集的语言来说,情况并非如此。

例如,此技术用于采用"资源获取即初始化"范式:当调用对象构造函数时获取资源,编译器自动调用其析构函数以释放正常和异常(异常)情况下的资源(检查此问题)。

您可以利用构造/破坏时间知识的常见地方有

  • 块:在块的末尾调用"stack allocated"对象的析构函数

    1
    2
    3
    4
    void function()
    {  Class foo = Object(resource);
       other_operations();
    }  // destructor for foo is called here
  • 函数调用:调用函数时也会发生"堆栈分配"

    1
    2
    3
    4
    5
    6
    void function()
    {  another_function ( Class(resource)  );
       // destructor for the unnamed object is called
       // after another_function() returns (or throws)
       other_operations();
    }
  • 包含对象的构造/销毁:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class Foo
    {  Class sentry;
       public: Foo()
       { // Constructor for sentry is called here
          something();
       }        
       public: ~Foo()
       {
          something();
       }  // destructor for sentry is called here
    };

在STL中有一个名为sentry的类(更确切地说,是istream::sentry的类),它实现了上面描述的第三种模式。所以我认为这就是一些程序员所说的"哨兵对象"。

但事实上,上述任何一类的物品都可以称为"哨兵物品"。他们是"哨兵",因为他们确保即使某些东西抛出异常,也不会错过这些难以捉摸的对象析构函数(所以他们类似于块/类的守护者)。

在这个问题中有更多的哨兵目标例子。

您可以看到与面向方面编程的关系;这些对象类似于"方面",在封闭块的开始/结束处有切点,"在包含对象的构造/销毁处"等,但是这些"方面"必须出现在它们所涉及的代码中。因此,与最初的call/return功能相比,它们的"方面性"要小一些;相反,应该在类的每个功能中插入一个sentry对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class X{
  struct Sentry {
     Sentry() { /* call() */}
    ~Sentry() { /* return() */};
  };

  void member_function()
  { Sentry();
    /* operations */
  }

  void another_member_function()
  { Sentry();
    /* operations */
  }
};


与AOP的区别在于,它必须通过将哨兵显式地放在函数体或类定义中的某个位置来协作完成。

如果不修改目标函数或类,则无法捕获调用。


下面是一个例子,一个哨兵类将一个变量重置为它的旧值。