putting function definitions in header files
Asked Answered
L

4

19

If you want to put function definitions in header files, it appears there are three different solutions:

  1. mark the function as inline
  2. mark the function as static
  3. put the function in an anonymous namespace

(Until recently, I wasn't even aware of #1.) So what are the differences to these solutions, and when I should I prefer which? I'm in header-only world, so I really need the definitions in the header files.

Latinize answered 20/10, 2011 at 9:37 Comment(3)
You forgot: Turn them into function templates. That's what I usually prefer.Selfassertion
don't use static that leads to many different copies and madness.Lanate
The "one copy in each anonymous namespace" solution leads to the same madness.Converter
C
19

The static and unnamed namespace versions end up being the same: each Translation Unit will contain it's own version of the function, and that means that given a static function f, the pointer &f will be different in each translation unit, and the program will contain N different versions of f (more code in the binary).

This is not the right approach to provide a function in a header, it will provide N different (exactly equal) functions. If the function contains static locals then there will be N different static local variables...

EDIT: To make this more explicit: if what you want is to provide the definition of a function in a header without breaking the One Definition Rule, the right approach is to make the function inline.

Caras answered 20/10, 2011 at 10:24 Comment(7)
So inline is the right approach? It would be nice if you made that explicit.Latinize
My understanding on this was similar & I posted the same as an answer but then I deleted it,Since I was a bit stuck up with the Q, How making a function defined in header as inline,makes it bypass the ODR?, I thought Section $3.2/5 addresses this but I was not sure.This is probably more detail than seeked in the Q but can you please ellaborate on this.Everyone
@Als: 3.2/3 Every program shall contain exactly one definition of every non-inline function or object that is used in that program; no diagnostic required. [...] An inline function shall be defined in every translation unit in which it is used. (Wording from C++03, but the same can be found in C++11 where used is ODR-used)Sulfuric
@DavidRodríguez-dribeas: +1,that sums it up for me.Thanks :)Everyone
@Nik-Lz: The difference is in fact 1 vs. N. In the inline case, there may be multiple definitions, but there's a single function in the program. In practical terms, the linker will remove all but one definition (ignoring actual inlining, which is orthogonal) and there will be a guarantee that if there's an out of line definition it will be unique (single address). In the case of static there will be N functions, each with its own address, each with each own copies of any local static variables, those are different functions.Sulfuric
@Nik-Lz: not sure how clear it is, but the keyword inline is orthogonal to whether the function code will be inlined at the call sites or not. The contents of a static function can be inlined (and frequently are if they are simple enough, and not used from many places), and the contents of an inline function may not be inlinable (for example if it uses recusion that cannot be turned into a loop --i.e. not tail-recursion)Sulfuric
@Nik-Lz: The simplest example would be int foo() { static int value; return ++value; }, in a header. Create multiple translation units that call the function. In the case of inline each call will get a different value that is one more than the previous function call, in the case of static they will all get 1 as the value.Sulfuric
T
4

As far as I know, only inline and template functions can be defined in header files.

static functions are deprecated, and functions defined in an unnamed namespace should be used instead (see 7.3.1.1 p2). When you define a function in an unnamed namespace in a header, then every source code including that header (directly or indirectly) will have an unique definition (see 7.3.1.1 p1). Therefore, functions should not be defined in the unnamed namespace in header files (only in source files).

The standard referenced are from the c++03 standard.

EDIT:

Next example demonstrates why functions and variables shouldn't be defined into unnamed namespace in headers :

ops.hpp contains:

#ifndef OPS_HPP
#define OPS_HPP
namespace
{
int a;
}
#endif

dk1.hpp contains:

#ifndef DK1_HPP
#define DK1_HPP
void setValue();
void printValue();
#endif

dk1.cpp contains:

#include "dk1.hpp"
#include "ops.hpp"
#include <iostream>

void setValue()
{
    a=5;
}
void printValue()
{
    std::cout<<a<<std::endl;
}

dk.cpp contains :

#include "dk1.hpp"
#include "ops.hpp"
#include <iostream>

int main()
{
    // set and print a
    setValue();
    printValue();

    // set and print it again
    a = 22;
    std::cout<<a<<std::endl;

    // print it again
    printValue();
}

Compile like this:

g++ -ansi -pedantic -Wall -Wextra dk.cpp dk1.cpp

and the output :

5
22
5

ops the variable a is different for the source file dk1.cpp and dk.cpp

Taveras answered 20/10, 2011 at 10:17 Comment(5)
There's nothing wrong per se with having anonymous namespaces with function definitions in headers - it's not a violation of the ODRStorybook
static functions were never deprecated, only static objects (before C++11).Strew
@awoodland: There is nothing inherently wrong from the point of view of the compiler, but most probably there is from the point of view of the program. What looks like a function in a header is actually many functions in different translation units, it will generate extra code (larger binary, worse performance of the instruction cache), and if the function contains local static variables, each translation unit will refer to it's own version. The compiler will do that and be happy. But whoever needs to debug that in the future will not be so happy.Sulfuric
@DavidRodríguez-dribeas - that's an interesting decision, do you have a reference for the rationale behind this reversal?Storybook
@awoodland: True, but it will tend to bloat the code (by generating multiple separate copies of each function), and can lead to subtle bugs when static data in the functions is not shared between translation units.Strew
S
0

static functions (equivalent to anonymous namespace) receive different copies for each TU. If the function is re-entrant this is basically identical (some compilers might have assembly-level differences) but if it isn't then it will have different static data for each TU. Inline functions are folded- that is, they have only one copy of static data for every TU.

Sulphurous answered 20/10, 2011 at 9:39 Comment(2)
@TonyK: While I agree to the suggestion of not using abbrevatons and using the full notations,I strongly disagree with the OP obviously isn't an expert.The OP is one of the few experts in SO who really understands C++ to the core.Everyone
Well, I decided to delete my comment, but too late...So let me restate it here: Using an abbreviation like TU assumes a level of experience in your reader that renders your explanation superfluous. (Unless, apparently, your reader is FredOverflow.) And BTW, it means Translation Unit.Servitor
A
0

You could consider wrapping the methods in a class instead of a namespace. Declare these methods as static and delete the constructor of the class to reinforce that this is not an object to be instantiated.

struct FooNamespace
{
    FooNamespace() = delete;

    static FooMethod1() {
        ...
    }
    static FooMethod2() {
        ...
    }

};

You get the same general behavior as it belonging to a namespace with only a single implementation.

Amalita answered 15/10, 2019 at 18:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.