LCOV - code coverage report
Current view: top level - snapdev - safe_object.h (source / functions) Coverage Total Hit
Test: coverage.info Lines: 100.0 % 23 23
Test Date: 2026-02-16 17:48:13 Functions: 100.0 % 11 11
Legend: Lines: hit not hit

            Line data    Source code
       1              : // Copyright (c) 2019-2026  Made to Order Software Corp.  All Rights Reserved
       2              : //
       3              : // https://snapwebsites.org/project/snapdev
       4              : // contact@m2osw.com
       5              : //
       6              : // This program is free software: you can redistribute it and/or modify
       7              : // it under the terms of the GNU General Public License as published by
       8              : // the Free Software Foundation, either version 3 of the License, or
       9              : // (at your option) any later version.
      10              : //
      11              : // This program is distributed in the hope that it will be useful,
      12              : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      13              : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14              : // GNU General Public License for more details.
      15              : //
      16              : // You should have received a copy of the GNU General Public License
      17              : // along with this program.  If not, see <https://www.gnu.org/licenses/>.
      18              : #pragma once
      19              : 
      20              : /** \file
      21              :  * \brief Implementation of a safe object template.
      22              :  *
      23              :  * Once in a while, an object (such as a C resource) is created and it is
      24              :  * a bare pointer for some time. This template allows you to make sure that
      25              :  * the object will either be deleted (i.e. if an exception or early return
      26              :  * happens) or safely saved in a place where it will be remembered properly.
      27              :  *
      28              :  * You want to supply the bare pointer type, the pointer itself, and when
      29              :  * required a deleter. By default, the deleter is simply uses the delete
      30              :  * operator.
      31              :  *
      32              :  * The main difference with this safe_object template, compared to using
      33              :  * a smart pointer, is that you have the ability to safely take the pointer
      34              :  * out of the safe_object with the release() function. After that one
      35              :  * call, the object pointer is set to nullptr and thus the safe_object
      36              :  * will not release it.
      37              :  *
      38              :  * \code
      39              :  *     {
      40              :  *         snapdev::safe_object<my_type *> so;  // create the safe object first
      41              :  *         my_type * obj(new my_type);          // create your object
      42              :  *         so.make_safe(obj);                   // make it safe for a while
      43              :  *
      44              :  *         ...your statements while obj isn't safe...
      45              :  *
      46              :  *         // if an interrupt happened before this statement, then obj
      47              :  *         // was safely deleted
      48              :  *         //
      49              :  *         so.release();
      50              :  *     }
      51              :  * \endcode
      52              :  *
      53              :  * You should not try to use the `safe_object<>` template as a replacement
      54              :  * of the `shared_ptr<>` template. It is not the same. You cannot
      55              :  * copy a `safe_object<>`.
      56              :  */
      57              : 
      58              : namespace snapdev
      59              : {
      60              : 
      61              : namespace detail
      62              : {
      63              : 
      64              : 
      65              : 
      66              : template<typename T>
      67            6 : void default_safe_object_deleter(T ptr)
      68              : {
      69            6 :     delete ptr;
      70            6 : }
      71              : 
      72              : 
      73              : 
      74              : } // namespace detail
      75              : 
      76              : 
      77              : /** \brief Make a pointer of a given type safe.
      78              :  *
      79              :  * This class is used to make a variable safe. This is important if you
      80              :  * allocate a resource, do further initialization that can throw, and then
      81              :  * safe the resource pointer as required.
      82              :  *
      83              :  * This is particularly useful if you need to allocate multiple objects
      84              :  * in a row and need to save pointers until all can safely be saved in a
      85              :  * final destination.
      86              :  *
      87              :  * To handle a bare pointer, make sure to pass that as the type T.
      88              :  *
      89              :  * \tparam T  The type of the value to save and restore.
      90              :  * \tparam deleter  A function called when the object needs to be deleted.
      91              :  */
      92              : template<typename T, void(deleter)(T) = detail::default_safe_object_deleter>
      93              : class safe_object
      94              : {
      95              : public:
      96              :     /** \brief Create a safe_object on your stack.
      97              :      *
      98              :      * This object is expected to be created on your stack.
      99              :      *
     100              :      * An object of this type cannot be copied. It is expected to only be
     101              :      * used on the stack so it goes out of scope at the next `}`.
     102              :      *
     103              :      * \note
     104              :      * For that reason the copy and assignment operators are deleted.
     105              :      */
     106           22 :     safe_object()
     107           22 :     {
     108           22 :     }
     109              : 
     110              :     /** \brief Prevent copying safe_object's.
     111              :      *
     112              :      * Delete the copy operator so you can't copy these objects. There is not
     113              :      * reference counter or similar feature so we need to make sure you
     114              :      * cannot copy (like unique_ptr) or transfer (like auto_ptr) ownership.
     115              :      */
     116              :     safe_object(safe_object const &) = delete;
     117              : 
     118              :     /** \brief Prevent assignment of safe_object's.
     119              :      *
     120              :      * Delete the assignment operator so you can't copy these objects. There
     121              :      * is not reference counter or similar feature so we need to make sure you
     122              :      * cannot copy (like unique_ptr) or transfer (like auto_ptr) ownership.
     123              :      */
     124              :     safe_object & operator = (safe_object const &) = delete;
     125              : 
     126              :     /** \brief Delete the value is not yet released.
     127              :      *
     128              :      * On destruction, the value gets deleted by the defaulr ot user
     129              :      * specified deleter.
     130              :      */
     131           22 :     ~safe_object()
     132              :     {
     133           22 :         cleanup();
     134           22 :     }
     135              : 
     136              :     /** \brief Update the value through the safe object.
     137              :      *
     138              :      * This function allows you to update the value. Since you are
     139              :      * expected to have direct access to the variable saved in this
     140              :      * object, it is likely not very useful to call this function.
     141              :      * It is here primarily for completeness.
     142              :      *
     143              :      * \warning
     144              :      * This function calls the cleanup() function to make sure that
     145              :      * if a previous object was present, it gets deleted.
     146              :      *
     147              :      * \param[in] object  The object to protect from exceptions.
     148              :      */
     149           22 :     void make_safe(T object)
     150              :     {
     151           22 :         if(object != f_object)
     152              :         {
     153           22 :             cleanup();
     154           22 :             f_released = false;
     155           22 :             f_object = object;
     156              :         }
     157           22 :     }
     158              : 
     159              :     /** \brief Release the value.
     160              :      *
     161              :      * This function releases the value, which means the deleter will
     162              :      * not be called against it.
     163              :      *
     164              :      * This or another object can be re-added by calling the
     165              :      * make_safe() function again.
     166              :      */
     167           11 :     void release()
     168              :     {
     169           11 :         f_released = true;
     170           11 :     }
     171              : 
     172              :     /** \brief Get a reference to the saved value.
     173              :      *
     174              :      * This function returns a reference to the saved value. Since it
     175              :      * is a constant, returning a reference is safe even in a
     176              :      * multi-threaded environment.
     177              :      *
     178              :      * If you used the constructor with a `restore` parameter, then that
     179              :      * value is returned by this function.
     180              :      *
     181              :      * \note
     182              :      * It is not possible to change the saved value.
     183              :      *
     184              :      * \return The protected object.
     185              :      */
     186              :     T protected_object() const
     187              :     {
     188              :         return f_object;
     189              :     }
     190              : 
     191              :     /** \brief Clean up the object if not yet released.
     192              :      *
     193              :      * This function makes sure to call the deleter on the currently
     194              :      * protected object, contrary to the release() function which
     195              :      * makes sure not to call the deleter.
     196              :      */
     197           44 :     void cleanup()
     198              :     {
     199           44 :         if(!f_released)
     200              :         {
     201           11 :             f_released = true;
     202           11 :             deleter(f_object);
     203              :         }
     204           44 :     }
     205              : 
     206              : private:
     207              :     /** \brief The object to protect.
     208              :      *
     209              :      * This field is the object to protect. In most cases, this is going
     210              :      * to be a pointer. It could very well be an identifier or another type
     211              :      * of resource handle.
     212              :      */
     213              :     T f_object = T();
     214              : 
     215              :     /** \brief Whether the value was released or not.
     216              :      *
     217              :      * This value tells us whether the release() function was called (true)
     218              :      * or not (false).
     219              :      *
     220              :      * When this field is `true` the deleter is not called against
     221              :      * f_object. By default, this value is true.
     222              :      */
     223              :     bool f_released = true;
     224              : };
     225              : 
     226              : 
     227              : 
     228              : } // namespace snapdev
     229              : // vim: ts=4 sw=4 et
        

Generated by: LCOV version 2.0-1

Snap C++ | List of projects | List of versions