57

I was looking at the request parser from the boost::asio example and I was wondering why the private member functions like is_char() are static? :

class request_parser
{
  ...
  private:
    static bool is_char(int c);
  ...
};

It is used in the function consume which is not a static function:

boost::tribool request_parser::consume(request& req, char input)
{
  switch (state_)
  {
    case method_start:
    if (!is_char(input) || is_ctl(input) || is_tspecial(input))
    {
      return false;
    }
    ...

Only member functions can call is_char() and no static member function is calling is_char(). So is there a reason why these functions are static?

rve
  • 5,897
  • 3
  • 40
  • 64

5 Answers5

90

This function could easily have been made freestanding, since it doesn't require an object of the class to operate within. Making a function a static member of a class rather than a free function gives two advantages:

  1. It gives the function access to private and protected members of any object of the class, if the object is static or is passed to the function;
  2. It associates the function with the class in a similar way to a namespace.

In this case it appears only the second point applies.

Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
  • 1
    Indeed, that #1 I forgot about in my answer. `+1` from me, too. – sbi Jun 22 '11 at 20:44
  • 1
    If a static member function takes an instance of that class as an argument, isn't it conceptually a non-static member function? – Oliver Charlesworth Jun 22 '11 at 22:24
  • 2
    @Oli: Yes, you basically made the `this` pointer explicit in the arguments. – Frerich Raabe Jun 23 '11 at 07:30
  • 2
    +1 for the first bullet, I forgot this. One addition - it also gives the function access to private and protected members of the class itself (read: static variables with private or protected visibility). – Frerich Raabe Jun 23 '11 at 07:31
  • @Mark Ransom Could you please show me a simple example to fully understand that#1? – John May 10 '22 at 01:51
  • @John one common use case is for C style callback functions that aren't tied to a class, e.g. OS APIs. `static void MyClass::callback(void * vp) { ((MyClass*)vp)->DoSomethingPrivate(); }` – Mark Ransom May 10 '22 at 03:15
  • @MarkRansom Any benefit for this case? Why not just use it as a freestanding method? – John May 10 '22 at 03:30
  • @John a freestanding method can't be called on its own, it needs to be called from an object. So the callback has to be two parts - the first part converts the `void*` pointer to an object pointer, then the object can call its method. You can of course define a function that isn't part of the class for this pattern, but it won't have access to private class methods. Often the callback method should be private so nobody is tempted to call it outside its intended purpose. – Mark Ransom May 10 '22 at 05:04
  • @MarkRansom Thank you for the detailed explanation. My understanding of this matter is at a different level with your generous help. I can understand that **It gives the function access to private and protected members of any object of the class, if the object(or the pointer of the object) is passed to the function;** now. But what do you mean by " ***if the object is static*** or is passed to the function;"? Though I thought and thought, I still can't understand why you mention it, I really conscious about that.I can't see any relation with the **static object** indeed. – John May 10 '22 at 05:59
  • @John a class can have static data members as well, and a static member function has access to those. I probably worded that badly. – Mark Ransom May 10 '22 at 12:11
  • @MarkRansom If I understand you correctly, you mean that ***It gives the function access to private and protected members of any member object\variable declared as static.*** Am I right? – John May 10 '22 at 12:38
24

So is there a reason why these functions are static?

Non-static member functions have a hidden additional parameter called this. Passing this doesn't come for free, so making a private function static can be seen as a means of optimization.
But it can also be seen as a means of expressing your requirements/design in your code: If that function doesn't need to refer to any member data of the class, why should it be a non-static member function?

However, changing the type of any member function, public or private, static or not, will require all clients to recompile. If this needs to be done for a private function which those clients can never use, that's a waste of resources. Therefore, I usually move as many functions as possible from the class' private parts into an unnamed namespace in the implementation file.

sbi
  • 219,715
  • 46
  • 258
  • 445
  • 1
    +1 for the last paragraph: "If this needs to be done for a private function which those clients can never use, that's a waste of resources. Therefore, I usually move as many functions as possible from the class' private parts into an unnamed namespace in the implementation file.". In general, one should stash entities in the smallest encapsulation box possible. Private methods and data members are not accessible to any client outside the class, I never understood why they have to be declared in the class header... but I digress – András Aszódi Sep 10 '20 at 12:44
  • @LaryxDecidua: Name lookup would do weird things if different files saw a class as having a different set of members. – Davis Herring Jan 07 '22 at 01:37
10

For this specific example, the choice for a static is_char() is most likely a documentation one. The intent is to impress upon you that the is_char() method is not contrained to a specific instance of the class, but the functionality is specific to the class itself.

In other words, by making it static they are saying that is_char() is a utility function of sorts...one which can be used irrespective of the state of a given instance. By making it private, they are saying that you (as a client) should not try to use it. It either does not do what you think it does, or is implemented in a very constrained, controlled way.

@Mark Ransom's answer brings up a good point for the practical use of a private static member function. Specifically, that member function has access to private and protected members of either a static object or a passed instance of an instantiated object.

One common application of this is to abstract a pthread implementation in somewhat of an object oriented way. Your thread function must be static, but declaring it private limits the accessibility of that function to the class (to all but the most determined). The thread can be passed an instance of the class it's being "hidden" in, and now has access to perform logic using the object's member data.

Simplistic Example:

[MyWorkerClass.h]
...
public:
    bool createThread();

private:
    int getThisObjectsData();

    pthread_t    myThreadId_;
    static void* myThread( void *arg );
...

[MyWorkerClass.cpp]
...
bool MyWorkerClass::createThread()
{
    ...
    int result =  pthread_create(myThreadId_, 
                                 NULL,
                                 myThread), 
                                 this);
    ...
}

/*static*/ void* MyWorkerClass::myThread( void *arg )
{
    MyWorkerClass* thisObj = (MyWorkerClass*)(arg);
    int someData = thisObj->getThisObjectsData();
}
...
dolphy
  • 6,218
  • 4
  • 24
  • 32
  • `arg->getThisObjectsData()` should be `thisObj->getThisObjectsData()` ? – rve Jun 23 '11 at 07:42
  • @rve What do you mean by "to all but the most determined"? Could you please explain that for me? – John May 10 '22 at 06:16
  • @John Declaring something private limits the accessibility of that function to the class, but if you are determined enough, you can still access private functions from elsewhere. However that would be an ugly hack which no one should ever do in production code. – rve May 24 '22 at 18:21
3

It's static, since it doesn't require access to any member variables of request_parser objects. Hence, making it static decouples the function since it reduces the amount of state which the function can access.

For what it's worth, it would have been even better if this function wasn't part of the request_parser class at all - instead, it should have been (possibly in a namespace) a free function in the .cpp file.

Frerich Raabe
  • 90,689
  • 19
  • 115
  • 207
  • Could you please give detailed reasons for it should have been (possibly in a namespace) a free function in the .cpp file? – John May 10 '22 at 06:20
1

The point isn't where it is used. The question is what it uses. If its definition doesn't use any nonstatic members, I would make the function static, according to the same principle that I wouldn't pass a redundant parameter to any function (unless they were to be used in overload resulion)

Armen Tsirunyan
  • 130,161
  • 59
  • 324
  • 434