tags:

views:

299

answers:

3

I answered this question, and Potatoswatter answered too as

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

I am not familiar with using sentry objects in C++. I thought they were limited to input and output streams.

Could somebody explain to me about C++ sentry objects as well as how to use them as an around interceptor for one or more methods in a class ?

i.e. How to do this ?

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.

A: 

Here is an example for a sentry class which resets a variable to its old value.

sbi
I don't see the answer to the question in the post.Is a sentry object a pattern ?
Romain Hippeau
@Romain: Then I misread your question. i thought you were asking what a sentry object is and how to use it.
sbi
@Romain: yes, it's a pattern and not a particular class. You can even use a local, non-derived, anonymous class within the function as a sentry.
Potatoswatter
+9  A: 

Sentry object is a pattern, but I'm not sure which one of those below (maybe all).

C++ programs often heavily rely on knowledge when exactly an object (possibly of a user-defined class) is destroyed, i.e. when its destructor is called. This is not the case for languages with garbage collection.

This technique is used, for example, to embrace "Resource Acquisition Is Initialization" paradigm: you acquire resources when an object constructor is called, and the compiler automatically calls its destructor to free resources in both normal and abnormal (exceptional) situations (check this question).

Common places where you can utilize the knowledge of construction/destruction timing are

  • Blocks: a destructor for "stack-allocated" object is called at the end of the block

    void function()
    {  Class foo = Object(resource);
       other_operations();
    }  // destructor for foo is called here
    
  • Funciton calls: "stack-allocation" also happens when you call a function

    void function()
    {  another_function ( Class(resource)  );
       // destructor for the unnamed object is called
       // after another_function() returns (or throws)
       other_operations();
    }
    
  • Construction/Destruction of the containing object:

    class Foo
    {  Class sentry;
       public: Foo()
       { // Constructor for sentry is called here
          something();
       }        
       public: ~Foo()
       {
          something();
       }  // destructor for sentry is called here
    };
    

In STL there's a class called sentry (more exactly, istream::sentry), which implements the third pattern of those described above. So I think that is what some programmers refer to as "sentry object".

But in fact any of the above objects of class Class may be called "sentry object". They're "sentry" because they ensure that these elusive object destructors are not missed even if something throws an exception (so they are like guardians of the block/class, of sorts).

More sentry object examples are in that RAII question.


You can see a relation to aspect-oriented programming; these objects are something like "aspects", with cutpoints "at the beginning/ending of the enclosing block", "at construction/destruction of containing object" etc. But these "aspects" have to present in the code they aspectate. So they're less "aspective" compared to the original call/return functionality; instead, a sentry object should be inserted to each function of the class:

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

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

  void another_member_function()
  { Sentry();
    /* operations */
  }
};
Pavel Shved
+1 thx for taking the time to explain so well
Romain Hippeau
@Romian, no problem, I'm just doing my best to procrastinate doing my actual job >_<
Pavel Shved
@Pavel: Don't we all know this... `:)`
sbi
+2  A: 

The difference with AOP is that it has to be done cooperatively by putting the sentry explicitly somewhere inside the function body or class definition.

You cannot catch the calls without modifying the targeted function or class.

fa.