什么是C ++中的“哨兵对象”?

时间:2010-04-22 12:50:15

标签: c++ idioms

answeredquestionPotatoswatter answered

  

现代C ++等价物将是一个   哨兵对象:在它上构造它   函数的开头,用它   构造函数实现call(),和   在返回(或异常退出)时,它   析构函数实现

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

有人可以向我解释C ++哨兵对象以及如何将它们用作类中一个或多个方法的周围拦截器吗?

即。怎么做?

  

Sentry对象非常相似   确实。一方面他们需要   显式实例化(和   通过这个)但另一方面你   可以添加到他们,以便他们检查不   只有类的不变量但是   一些前/后的条件   手头的功能。

3 个答案:

答案 0 :(得分:16)

Sentry对象是一种模式,但我不确定下面哪一个(可能全部)。

当完全一个对象(可能是用户定义的类)被破坏时,即当它的析构函数被调用时,C ++程序通常严重依赖于知识。具有垃圾收集的语言不是这种情况。

例如,使用此技术来包含“资源获取是初始化”范例:在调用对象构造函数时获取资源,并且编译器自动调用其析构函数以在正常和异常(异常)情况下释放资源(选中this question)。

您可以利用建筑/破坏时间知识的常见地方

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

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

    void function()
    {  another_function ( Class(resource)  );
       // destructor for the unnamed object is called
       // after another_function() returns (or throws)
       other_operations();
    }
    
  • 构建/销毁包含对象

    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),它实现了上述第三种模式。所以我认为这是一些程序员所称的“哨兵对象”。

但事实上,类Class的任何上述对象都可以称为“哨兵对象”。他们是“哨兵”,因为他们确保这些难以捉摸的对象析构函数不会被错过,即使有什么东西会抛出异常(所以他们就像块/类的守护者一样)。

RAII question中有更多的哨兵对象示例。


您可以看到面向方面编程的关系;这些对象类似于“方面”,切割点“在封闭块的开头/结尾”,“在构造/破坏包含对象”等。但这些“方面”必须存在于他们所代表的代码。因此,与原始call/return功能相比,它们不那么“随意”;相反,应该将sentry对象插入到类的每个函数中:

class X{
  struct Sentry {
     Sentry() { /* call() */}
    ~Sentry() { /* return() */};
  };

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

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

答案 1 :(得分:3)

与AOP的不同之处在于,必须通过将哨兵明确地放在函数体或类定义中的某个位置来完成协作

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

答案 2 :(得分:2)

Here是哨兵类的一个示例,它将变量重置为旧值。