开发者

private static member function or free function in anonymous namespace?

开发者 https://www.devze.com 2023-03-17 22:47 出处:网络
I\'ve recently made a change stylistically and wanted to see how other c++ programmers felt about it and if there were an开发者_如何学运维y downsides to it.

I've recently made a change stylistically and wanted to see how other c++ programmers felt about it and if there were an开发者_如何学运维y downsides to it.

Essentially, when I needed a utility function which doesn't need access to a given class member, what I used to do was something like this:

file.h

class A {
public:
    // public interface
private:
    static int some_function(int);
};

file.cpp

int A::some_function(int) {
    // ...
}

But more recently, I have been preferring to do something more like this:

file.cpp

namespace {
    int some_function(int) {

    }
}
// the rest of file.cpp

Here's my thought process:

  • it's one less file the edit
  • simply having the function be listed in the header file can hint at implementation details which have no need to be exposed (even if not publically available).
  • if the prototype of the function needs to change, only one file needs to be recompiled.

The last one is the most compelling to me. So my question is: are there any downsides to this?

They are functionally equivalent for most purposes that I can think of. It kind of seems to me that a private static function can almost always be converted to a free function in an anonymous namespace.

EDIT: One thing that comes to mind is that a private static function would have access to private members if given a pointer to an object to operate on, but if that's the case, why not make it a non-static member?

What do you guys think?


If the function is only used in one source file, it makes perfect sense to define it there. If nobody else is using it, it doesn't belong in the header.

As you say, it reduces dependencies and can potentially save some recompiles.


I started doing this several years ago and never found any real draw backs. Anything that the object uses, but doesn't itself change the state of the object and doesn't need to be used anywhere else, I like to put in an anonymous namespace in the implementation file.


I can't see any downsides to using an anonymous namespace. If you can code the function usefully without access to the class members, then you should, because it decouples it from the class itself (like how the standard algorithms work on iterator pairs).


Personally, the only static functions I use are factory functions, like this

class Angle {
public:
    static Angle FromDegree (float v);
    static Angle FromRadians (float v);

    ...
private:
    Angle (float degree);
};

Anything that does not need private access is made a free function. Anything that is not part of the public interface is, if possible, not put in a public place (conforming to your new approach).

Scott Meyer's article "How Non-Member Functions Improve Encapsulation" roughly describes the same approach:

Minimalness and Encapsulation

In Effective C++, I argued for class interfaces that are complete and minimal. Such interfaces allow class clients to do anything they might reasonably want to do, but classes contain no more member functions than are absolutely necessary. Adding functions beyond the minimum necessary to let clients get their jobs done, I wrote, decreases the class's comprehensibility and maintainability, plus it increases compilation times for clients. Jack Reeves has written that the addition of member functions beyond those truly required violates the open/closed principle, yields fat class interfaces, and ultimately leads to software rot. That's a fair number of arguments for minimizing the number of member functions in a class, but now we have an additional reason: failure to do so decreases a class's encapsulation.

Of course, a minimal class interface is not necessarily the best interface. I remarked in Effective C++ that adding functions beyond those truly necessary may be justifiable if it significantly improves the performance of the class, makes the class easier to use, or prevents likely client errors. Based on his work with various string-like classes, Jack Reeves has observed that some functions just don't "feel" right when made non-members, even if they could be non-friend non-members. The "best" interface for a class can be found only by balancing many competing concerns, of which the degree of encapsulation is but one.

Still, the lesson of this article should be clear. Conventional wisdom notwithstanding, use of non-friend non-member functions improves a class's encapsulation, and a preference for such functions over member functions makes it easier to design and develop classes with interfaces that are complete and minimal (or close to minimal). Arguments about the naturalness of the resulting calling syntax are generally unfounded, and adoption of a predilection for non-friend non-member functions leads to packaging strategies for a class's interface that minimize client compilation dependencies while maximizing the number of convenience functions available to them.

It's time to abandon the traditional, but inaccurate, ideas of what it means to be object-oriented. Are you a true encapsulation believer? If so, I know you'll embrace non-friend non-member functions with the fervor they deserve.


Private static non-const variables are useless to any code not in the .cpp, so I always use an anonymous namespace like that.

Static const variables may document constraints and expectations that are useful to client code, so they go in the header.

Static functions may need access to private data members, so they go in the header if they have to.


If you're using a unity build (i.e. #including all the .cpp files of the project into one compilation unit in order to speed up compile times), you'll risk name collisions with other functions in anonymous namespaces.

That's about the only downside I've found.


The whole reason for static function as opposed to global function is that it accesses the private members of the class. If this is not true, use a free function. This analysis is not complete answer until we have all 3 alternative ways to do it:

free function:

void f() { /* cannot access private members of any class */ }

static function:

class A {
public:
   static void g() { /* can access private members of class A */ }
};

friend functions:

    class A {
    public:
       friend void h();
    };
    class B {
    public:
       friend void h();
   };
   void h() { /* can access private members of both class A and class B */ }

The real problem with how c++ does this is that the function call looks different:

int main() {
   f();
   A::g();
   h();
 }
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号