I'm learning the Gandiva module in Apache Arrow. I found that many APIs require parameters in the form of std::shared_ptr<T>*
, eg here is an typical API:
static inline Status Make(SchemaPtr schema, ConditionPtr condition, std::shared_ptr<Filter> *filter)
I don't understand why it uses a pointer to a shared_ptr
instead of a simple shared_ptr
. To my understanding, a raw pointer should be avoided in C as much as possible, and shared_ptr
is designed as an alternative to using raw pointers.
CodePudding user response:
This is a way for the API to "return" a shared_ptr
to you. I have not used this library, but here is an example of what an API like this might do:
static inline Status Make(SchemaPtr schema, ConditionPtr condition, std::shared_ptr<Filter> *filter) {
// ...more stuff here...
// Assign a new instance of shared_ptr to the variable that the caller passed in
*filter = std::make_shared<Filter>(...);
return Status{"ok"};
}
This is often called an "out" parameter and it is documented as such in the API you linked.
There are alternatives.
- The function can use references, but those can disguise the fact that out parameters are being used.
Make(a, b, c)
looks like passing in three normal parameters butMake(a, b, &c)
can tip someone off that out parameters are being used. This is one reason it is common to prefer pointers over references for out parameters. - The function could return a
std::tuple<Status, std::shared_ptr<Filter>>
instead.
Sometimes when using the raw pointer argument, the library may check if the pointer is null and not assign anything to it in that case. That would make the out parameter optional, which neither of these alternatives can handle. (here is an example of an API using the optional out parameter with a raw pointer: https://doc.qt.io/qt-6/qstring.html#toInt)
The general rule in modern c is to avoid using raw pointers when you want to control ownership. This example does not take ownership of the passed in pointer and so does not break that rule.
Some people conform to a stricter rule where they try to avoid pointers everywhere, but that is less popular.
CodePudding user response:
This is their code style convention for output parameters.
filter – [out] the returned filter object
Usage
std::shared_ptr<Filter> filter;
Filter::Make(..., &filter);
I would use
Status Make(..., std::shared_ptr<Filter> &filter);
std::shared_ptr<Filter> filter;
Filter::Make(..., filter);
Perhaps seeing the usage &filter
they know filter
is an output argument w/o looking at the function declaration.
Apache Arrow Development Guidelines - Code Style, Linting, and CI
- We prefer pointers for output and input/output parameters (the style guide recommends mutable references in some cases).