RAII and deduced template arguments
c++, c++11, raii, templates
Solution
There is a very simple solution: Use a reference to the temporary object instead of copying it into a local variable.
void func()
{
auto&& helper = makeRAIIHelper(someObj);
}
Problem
Here's an issue I often run into with RAII. I was wondering if anyone had a good solution for it. Start with your standard RAII utility class: ``` class RAIIHelper { RAIIHelper() { AcquireAResource(); } ~RAIIHelper() { ReleaseTheResource(); } }; ``` Now, for various reasons, I need to make it a template. Let's also say its constructor takes an argument of the template parameter type: ``` template <typename T> class RAIIHelper { RAIIHelper(T arg) { AcquireAResource(); } ~RAIIHelper() { ReleaseTheResource(); } }; ``` Now consider a use site: ``` void func() { RAIIHelper<SomeType> helper(someObj); } ``` It's annoying to have to write out `SomeType` when it can be deduced from `someObj`, so I write a helper function to deduce the type: ``` template <typename T> RAIIHelper<T> makeRAIIHelper(T arg) { return RAIIHelper<T>(arg); } ``` Now I can use it like so: ``` void func() { auto helper = makeRAIIHelper(someObj); } ``` Wonderful, right? Except there's a snag: `RAIIHelper` is now required to be copyable or movable, and the destructor - which releases the resource - can potentially be called twice: once for the temporary returned by `makeRAIIHelper`, and once for the local variable in the calling function. In practice, my compiler performs RVO and the destructor is called only once. However, this is not guaranteed. This can be seen from the fact that if I try to give `RAIIHelper` a `= delete`'d move constructor, the code no longer compiles. I could add additional state to RAIIHelper so that it knows not to call `ReleaseTheResource()` after it's been moved-from, but that's extra work that was unnecessary before I added `makeRAIIHelper()` to get the type deduction. Is there a way I can get the type deduction, without having to add extra state to `RAIIHelper`?