I'm interested in discussion on when *tors should be inline and when they should be defined in their cpp. I've been trying to conceive of when it would be beneficial to relieve the instance owner of an unnecessary call to a *tor and I'm about ready to hear some feedback from some other programmers.
The bottom-line is basically the same for any consideration of inlining or not: will the overhead of a call to a non-inline method be optimal or not. But *tors have a lot of hidden code, which makes a special discussion worthwhile.
Before I make my arguments I should point out that I my choice of words will be overly general, and there are some situations in which the cases I present don't apply:
- Sometimes *tors have much more explicit roles, such as allocating/deallocating memory, opening/closing files, and whatever. In those situations the question of inlining becomes more obvious, but for the sake of argument, I'm considering only those situations where the executable code is more hidden within the source code, so assume there's nothing between the braces in the *tors.
- If the class members, or the parent classes of the classes in question do not follow these rules I have set, then that will ruin the benfit of inlining. So in the following cases, let's assume that all of the classes whose definitions are hidden, also followed these principles of inlining.
- Virtual methods make for a very confusing cocktail of hidden code. First of all, ctors initialize virtual tables, and virtual pointers, and I'm not ready to tackle those. What's more, if a parent's method is virtual (such as a dtor) then all child methods are automatically virtual, regardless of whether or not these child methods use the virtual keyword or not. Finally, virtual methods can't be inline. You can try to declare them inline, but they won't be inline, and you'll just waste compiler cycles. So let's assume for simplicity that none of these classes have any virtual methods
- If the members need to be initialized to default values, it might be worthwhile to define the ctor in a cpp, relieving the burden on the instance owners to do so.
Case 1: a class with only POD members
Code:
class pod {
int i;
float f;
short s;
char c[11];
};
It might be considered good coding practise to define your *tors in the cpp here, but otherwise a complete waste of cycles and space. The space for all these members will be (de)allocated by the owner on the stack, if the instance is allocated on the stack, or contiguously on the heap. In either case, the instance owner will have to be (de)allocating the memory anyway, and a call to a non-inline *tor would be a waste of a call. Even if the members are to be initialized by with values from the instance owners like so:
Code:
pod _pod(5, 1.5, 14, "fred");
the instance owner would still have to marshal the data onto the stack (or registers, depending on the calling convention) and then the, ctor would have to go about extracting the data, and assigning the members itself. It would still be faster (and require no more code) to have the instance owners assign the members directly.
Case 2: The class has exactly 1 non-POD member
Code:
class more_complex {
int i;
char c[11];
a_class_wout_inline_star_tors m;
};
In this case it would still be worthwhile to leave your *tors inline. True, not only will the instance owners have to (de)allocate for i, c, and whatever m needs, but they will have to call the *tors for m. So what good would it do if instead of calling m's *tors directly, the instance owner calls *tors for more_complex, which then makes the calls to m's *tors?
Case 3: the class has more than 1 non-POD member
Code:
class still_more_complex {
int i;
char c[11];
a_class_wout_inline_star_tors m;
another_class_wout_inline_star_tors n;
};
Here it might not be worthwhile to have inline *tors. If you try to inline them, the instance owners will just have to call m's *tors and then n's *tors.
Case 4: the class is a child class
The way I see it, you can treat each parent like a class member. So if you have only 1 parent, it's as if you have only 1 non-POD class member, and if you have multiple inheritance, it's as if you have multiple non-POD members.
So am I right or am I wrong?