tags:

views:

150

answers:

2

In keeping with the practice of using non-member functions where possible to improve encapsulation, I've written a number of classes that have declarations which look something like:

void auxiliaryFunction(
        const Class& c,
        std::vector< double >& out);

Its purpose is to do something with c's public member functions and fill a vector with the output. You might note that its argument order resembles that of a python member function, def auxiliaryFunction(self, out).

However, there are other reasonable ways of choosing the argument order: one would be to say that this function resembles an assignment operation, out = auxiliaryFunction(c). This idiom is used in, for example,

char* strcpy ( char* destination, const char* source );

What if I have a different function that does not resemble a non-essential member function, i.e. one that initializes a new object I've created:

void initializeMyObject(
    const double a,
    const std::vector<double>& b,
    MyObject& out);

So, for consistency's sake, should I use the same ordering (mutable variable last) as I did in auxiliaryFunction?

In general, is it better to choose (non-const , const) over (const, non-const), or only in certain situations? Are there any reasons for picking one, or should I just choose one and stick with it?

(Incidentally, I'm aware of Google style guide's suggestion of using pointers instead of non-const references, but that is tangential to my question.)

+4  A: 

The STL algorithms places output (non-const) values last. There you have a precedent for C++ that everyone should be aware of.

I also tend to order arguments from important, to less important. (i.e. size of box goes before box-margin tweak value.)

(Note though: Whatever you do, be consistent! That's infinitely more important than choosing this or that way...)

Marcus Lindblom
+1  A: 

Few points that may be of help:

  • Yes, I like the idea of following the standard library's argument ordering convention as much as possible. Principle of least surprises. So, good to go. However, remember that the C standard library itself is not very well crafted, particularly if you look at the file handling API. So beware -- learn from these mistakes.

  • const with basic arithmetic types are rarely used, it'd be more of a surprise if you do.

  • The STL, even with its deficiencies provide, IMO, a better example.

  • Finally, note that C++ has another advantage called Return Value Optimization which is turned on in most modern compilers by default. I'd use that and rewrite your initializeMyObject or even better, use a class and constructors.

  • Pass by const-reference than by value -- save a lot of copying overhead (both time and memory penalties)

So, your function signature should be more like this:

 MyObject initializeMyObject(
    double a,
    const std::vector<double>& b,
    );

(And I maybe tempted to hide the std::vector<double> by a typedef if possible.)

In general, is it better to choose (non-const , const) over (const, non-const), or only in certain situations? Are there any reasons for picking one, or should I just choose one and stick with it?

Use a liberal dose of const whenever you can. For parameters, for functions. You are making a promise to the compiler (to be true to your design) and the compiler will help you along every time you digress with diagnostics. Make the most of your language features and compilers. Further, learn about const& (const-refernces) and their potential performance benefits.

dirkgently
Seth Johnson
@Seth Johnson: The downvote for this? As I said, I have never (==very, very rarely) come across production code using `const` with `int` or `floats` -- not suggesting it is wrong or bad style. Also, remember that you are passing the `double` by value -- so a change to the value will not be reflected to the caller. Further, the particular example you posted, most modern compilers generate a warning for assignments withing conditionals. Finally, `typedef` is a trade-off. STL uses it extensively and I prefer to see concrete domain specific names instead of implementation details.
dirkgently
I didn't downvote it; I do appreciate your input despite its paternalistic tone.
Seth Johnson
@Seth Johnson: Paternalistic? I was only trying to make sure you realise that I am dishing out my subjective opinion and not silver bullets ;-)
dirkgently
@dirkgently: Sorry, I meant patronizing. ;) I use typedef a lot in traits classes, etc., but not with member functions or elsewhere in free-standing code. I also found [an instance](http://stackoverflow.com/questions/117293/use-of-const-for-function-parameters/117557#117557) of others using `const` in pass-by-value functions, so to each his own on that one.
Seth Johnson
@Seth Johnson: Why not update your question with this SO link? It may be helpful to others who are/will be viewing your question. (And yes, I have heard that one ...)
dirkgently