Argument order for mixed const and non-const pass-by-reference
In keeping with the practice of using non-member functions where possible to improve 开发者_如何学Cencapsulation, 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.)
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...)
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.
精彩评论