If a pointer is passed to a function for read only, then this pointer is an IN parameter.
If a pointer is passed to a function for read only, but this function makes a copy of the pointer to have access to it in module related functions for read only operations, this pointer is still IN.
If the function still uses the pointer as read only, but the other module related functions use the pointer for write operations, what does that make the pointer? An IN parameter, but without const? An in/out parameter?
Example of what I mean:
class SteeringWheel {
public: float rotation;
public: SteeringWheel(void) {
this->rotation = 0.f;
}
};
class Car {
private: SteeringWheel *steeringWheel;
public:
/**
* @param[?] steeringWheel Is the steering wheel in or in/out?
*/
Car (SteeringWheel *steeringWheel) {
this->steeringWheel = steeringWheel;
}
/**
* @param[in] degree Steering amount in degrees.
*/
void steer(float degree)
{
this->steeringWheel->rotation += degree;
}
};
int main(int argc, char **argv)
{
SteeringWheel steeringWheel();
/* car() uses steeringWheel as read only. */
Car car(&steeringWheel);
/* steer() uses steeringWheel from car() to write. */
car.steer(50.f);
return 0;
}
I believe that the in
and out
specifiers do not exactly mean what you think. From the doxygen documentation of the param
tag:
The \param command has an optional attribute, (dir), specifying the direction of the parameter. Possible values are "[in]", "[in,out]", and "[out]", note the [square] brackets in this description. When a parameter is both input and output, [in,out] is used as attribute.
The direction of the parameter usually mean the following:
in
: The parameter is injected into the function as input, but not written to.out
: The parameter is injected into the function, but not as input. Rather, it is written to by the function.in, out
: The parameter is injected into the function as input and is eventually written to by the function.In your example:
/**
* @param[?] steeringWheel Is the steering wheel in or in/out?
*/
Car (SteeringWheel *steeringWheel) {
this->steeringWheel = steeringWheel;
}
I think the steeringWheel
parameter is in
because you inject it and use it in your method. However, you never write to it (i.e. to the parameter itself), so it is not out
. In other words, you only use your method to inject an address to your function, nothing else. The same apply for your second method, where you inject the degree
parameter, but never write to it.
To clarify a bit more on the meaning of in
and out
, here is an example of an out
parameter:
/**
* @param[out] p_param We write to the parameter!
*/
void makeFour(int * p_param)
{
*p_param = 4; // Out because of this line!
}
Notice that we write a new value directly into the parameter. This is the meaning of out: information comes out of the method through the parameter. You can now write:
int main()
{
int myInt = 0;
std::cout << myInt; // prints 0.
makeFour(&myInt); // p_param == &myInt here.
std::cout << myInt; // prints 4: the method wrote directly
// in the parameter (out)!
return 0;
}
Hope this helps!
It is not easy to decide, but I would still mark your parameter as in,out
(or out
), as it is a pointer to a non-const object, and you may change the state of that outside object directly or indirectly later - as in your example.
Marking it in
hides the detail that the pointed SteeringWheel
object may change later upon usage of Car
.
Also, it can puzzle users why an input only pointer parameter is not marked const
.
Making it in,out
may not be accurate completely, but is surely more error prone.
An alternative could be something like the following (a note regarding the lifetime of the SteeringWheel should come handy here anyway):
/**
* @param[in] steeringWheel Pointer to the SteeringWheel object.
* @warning The memory address of the pointed object is saved.
* It must outlive this object, and can change upon usage of this object.
*/
Car (SteeringWheel *steeringWheel) {
this->steeringWheel = steeringWheel;
}
But I would just probably stick with marking it in,out
.
Specifying the direction of parameters in C++ may be complicated, and frankly speaking, I am not too much in favor of them, as having tokens for pointers, references, and the keyword for constness provide enough information in the signature on how a parameter may be used. Thus, marking it in the DoxyPress documentation is a bit redundant, not expressive enough (as your example shows), and may get out of sync with the implementation. Documenting parameter directions may play a bigger role in case of other languages that lack these additional constructs in function signatures.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With