It depends. Consider this example:
struct example {
~example() { std::cout << "bye\n"; }
};
example* some_lib_function_A(){
return new example;
}
The library returns you a raw pointer to a dynamically allocated object. That's not nice, and to avoid dealing with the raw owning pointer you can wrap some_lib_function_A
into a function that returns a smart pointer that manages the object.
However, the library might also do something along the line of this (just for the sake of the argument. It should rather return a reference):
example* some_lib_function_B() {
static example ex;
return &ex;
}
And in this case you cannot delete
the returned pointer without running into problems.
Complete example:
#include <memory>
#include <iostream>
struct example {
~example() { std::cout << "bye\n"; }
};
example* some_lib_function_A(){
return new example;
}
example* some_lib_function_B() {
static example ex;
return &ex;
}
template <typename F>
std::unique_ptr<example> wrap(F f){
std::unique_ptr<example> res;
res.reset(f());
return res;
}
int main() {
wrap(some_lib_function_A);
wrap(some_lib_function_B); // free(): invalid pointer
}
The first line in main
does what you would expect, but the second line causes undefined behavior. Thats the reason the linked answer says that it is bad to write a function along the line of:
std::unique_ptr<example> wrap_bad(example& ex) {
std::unique_ptr<example> res;
res.reset(&ex);
return res;
}
Because you cannot know if the example
passed to the function was dynamically allocated or not. The function is lying about what it does, because a function taking a reference has no business in dealing with lifetime of its parameter. It can be used correctly, but it has great potential to be used wrong.
You have to read the libraries documentation and find out what the library expects you to do with the pointer. Sometimes you must call some library function clean_up(ex)
for proper clean up, in which case you can wrap the library clean up function in a custom deleter.