1

Is std::function smart in nature like std::shared_ptr and std::unique_ptr? I guess no? I have a std::function which is a class member like below.

class MyClass {
    typedef std::function<void(void)> Func;
    Func m_func;

public:
    MyClass() {
        m_func = []() {
            std::cout << "Func called" << std::endl;
        }
    }

    ~MyClass() {
       m_func = nullptr; // Is this required? 
    }
}

Question:
Is it mandatory to assign nullptr to m_func in the destructor? Or should I make m_func into a smart pointer by doing something like below? Or is it that m_func is smart by default and implicitly follows RAII?

class MyClass {
    typedef std::function<void(void)> Func;
    std::unique_ptr<Func> m_func;

public:
    MyClass() {
        m_func = std::make_unique<Func>();
        *m_func = []() {
            std::cout << "Func called" << std::endl;
        }
    }

    ~MyClass() {
       // auto released
    }
}
Mat
  • 202,337
  • 40
  • 393
  • 406
AdeleGoldberg
  • 1,289
  • 3
  • 12
  • 28
  • `std::function` is very, very smart. Follow the link you posted to the destructor section. – Mat May 04 '20 at 19:52
  • Ok. Sounds like I dont need to wrap it in a unique or shared pointer. – AdeleGoldberg May 04 '20 at 19:59
  • A bit strange that it is not mentioned to be smart in official documentation at https://en.cppreference.com/w/cpp/utility/functional/function. Official documentation rather mentions something like this in the Notes which is a bit confusing and sounds non RAII - "Care should be taken when a std::function whose result type is a reference is initialized from a lambda expression without a trailing-return-type." – AdeleGoldberg May 04 '20 at 20:15
  • 1
    That note doesn't really have much to do with your question. See [`std::function::~function`](https://en.cppreference.com/w/cpp/utility/functional/function/~function) for the direct answer to your question: _Destroys the std::function instance. If the std::function is not empty, its target is destroyed also._ – Miles Budnek May 04 '20 at 20:28
  • I'm pretty sure that all std classes respect rule of 3/5/0 even if joinable `std::thread` might be considered special ;-) – Jarod42 May 04 '20 at 21:07

1 Answers1

2

std::function has a destructor that deletes any resources it managed, if there are any. This line:

   m_func = nullptr; // Is this required? 

is never required. A class members destructors are called automatically and if not, assigning nullptr is never "the right" thing. If m_func was a pointer you would loose the pointers value and the ability to delete what it points to.

A bit strange that it is not mentioned to be smart in official documentation at ...

From cppreference on std::functions destructor:

Destroys the std::function instance. If the std::function is not empty, its target is destroyed also.

In general it is safe to assume that a class cleans up any resources it mangages in its detructor, otherwise it can be considered as broken. Cleaning up resources in destructors is not something that came new with smart pointers. Smart pointers only apply RAII wich was present in C++ always to pointers to encapsulate managment of dynamically allocated memory.

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
  • You _can_ assign a `nullptr` to a `std::function` object, which has the effect of clearing it out (it is part of the API). Your point about not needing to do it in the destructor is still valid, though. – Nevin May 05 '20 at 03:56
  • @Nevin thanks. I have to admit I wrote this in a hurry and wasnt sure on the `nullptr` think, I simply removed that sentence – 463035818_is_not_an_ai May 05 '20 at 07:08