// Copyright ⓒ 2018-2021 ThePhD.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//  See https://github.com/ThePhD/out_ptr/blob/master/docs/out_ptr.adoc for documentation.

# ztd.out_ptr at a glance

Have you ever wanted to pass a smart pointer like `std::unique_ptr` or `boost::shared_ptr` or `boost::intrusive_ptr` to a C API?

[source,cpp]
----
boost::shared_ptr<mll_driver> axis_driver;
mll_errno err = mll_driver_init(&axis_driver, 
	/* additional args ...*/);
if (err != MLL_SUCESS) {
	// etc. ...
}
----

The above code doesn't compile: the pointer may be "smart", but it isn't smart enough to return a `mll_driver**` when you do `&axis_driver` on it. It also makes it hard to retain the current deleter with a `shared_ptr`.

### So, try raw pointers?

Downgrading to a raw pointer and then inserting it into the pointer works, but is more verbose:

[source,cpp]
----
boost::shared_ptr<mll_driver> axis_driver;
mll_driver* raw_axis_driver = nullptr;
mll_errno err = mll_driver_init(&raw_axis_driver, 
	/* additional args ...*/);
if (err != MLL_SUCESS) {
	// etc. ...
}
axis_driver.reset(raw_axis_driver, mll_driver_free);
----

This works, but you need to call `.reset(...)` with the raw pointer and set everything up. Plus, there could be a lot of error handling code between us and the actual initialization call. Not to mention a thrown exception between the end of that call and `axis_driver.reset(...);` means you may have a leak.

### Let's make it simple and easy!

With ztd.out_ptr, we can do better. Get rid of the raw pointer and avoid potential memory or resource leakage by using this https://en.cppreference.com/w/cpp/language/raii[RAII] function:

[source,cpp]
----
using zop = ztd::out_ptr;

boost::shared_ptr<mll_driver> axis_driver(nullptr);
mll_errno err = mll_driver_init(zop::out_ptr(axis_driver, mll_driver_free), 
	/* additional args ...*/);
if (err != MLL_SUCESS) {
	// ...
}
----

No reset call, no inspecting for exception safety, and it remembers the deleter we passed in after `axis_driver` to safely and properly call `.reset()` for shared pointers that stores the deleter.

Welcome to ztd.out_ptr, the present and future of C API interoperation. This library automates the `.reset(...)` and -- sometimes additionally -- the `.release()` call when interfacing with C-style initialization functions which take an "output parameter" of `$$T**$$`.

- Use <<reference/out_ptr.adoc#ref.out_ptr.function, `ztd::out_ptr::out_ptr`>> when you just need to call `.reset()`, or use <<reference/inout_ptr.adoc#ref.inout_ptr.function, `ztd::out_ptr::inout_ptr`>>, when you need to call `.release()` and then `.reset()` (e.g., for a reallocating C function).
- Get started with the <<examples.adoc#examples,examples>>.
- Understand the pitfalls and problems that come with {cpp} and ztd.out_ptr by reading <<caveats.adoc#caveats, the Caveats>>.
- Read up on how to use it with your <<customization.adoc#customization, custom smart pointers>>, if you do not have a conforming interface!
- The exact interface requirements on the desired smart pointers can be seen in the <<reference.adoc#ref.api, reference documentation for the types produced by the factory functions>>.
- Peruse & use the advanced <<config.adoc#config, configuration options>> for safety, sanity checking, and speed!

C APIs might not be fun, but at least working with the pointers should feel easy and safe and simple!

Happy programming. ♥
