0

I tried to build a very simple version of std::function. Below the code of a very first version. My question is about the lifetime of the temporary object from the lambda-expression, because I'm actually storing a reference to it. Or is the lifetime of the object prolonged?

It tried to use a copy of the function (T mf instead of const T& mf inside struct F), but that gives an error due to the decaying of the function to a pointer.

#include <iostream>

template<typename T>
struct F {
    F(const T& f) : mf{f} {
        std::cout << __PRETTY_FUNCTION__ << '\n';
    }
    void test() {
        std::cout << __PRETTY_FUNCTION__ << '\n';
        mf();
    }
    const T& mf;
};

template<typename T>
struct F<T*> {
    F(T f) : mf{f} {
        std::cout << __PRETTY_FUNCTION__ << '\n';
    }
    void test() {
        std::cout << __PRETTY_FUNCTION__ << '\n';
        mf();
    }
    T* mf;
};

void g() {
    std::cout << __PRETTY_FUNCTION__ << '\n';
}

int main() {
    F<void(void)> f1(g);
    f1.test();

    auto g1 = g;

    F f2(g1);
    f2.test();

    F f3([](){ // lifetime?
        std::cout << __PRETTY_FUNCTION__ << '\n';
    });
    f3.test();

    auto l1 = [](){
        std::cout << __PRETTY_FUNCTION__ << '\n';
    };
    F f4(l1);
    f4.test();
}
wimalopaan
  • 4,838
  • 1
  • 21
  • 39
  • 1
    You indeed have lifetime issue. – Jarod42 Aug 25 '17 at 10:06
  • Do you see a way to solve this? – wimalopaan Aug 25 '17 at 10:12
  • 1
    Try [`std::decay_t`](http://en.cppreference.com/w/cpp/types/decay) – Passer By Aug 25 '17 at 10:17
  • You are using pointers and references. None of them ensure lifetime of the object being pointed. Variable `f3` has a lambda as an argument but this lamda creates a temporary variable which cannot be referenced (try moving instead). Even if you take a pointer from it it still will be destroyed when expression is evaluated (not until the end of scope even). – Teivaz Aug 25 '17 at 10:18
  • Solved: `std::decay_t` declares the member as function-pointer if `T` is a function. Otherwise it leaves `T` as it was. So in every case a copy ist made! And I don't have to use the partial specialization anymore. – wimalopaan Aug 25 '17 at 10:25

1 Answers1

2

You do have lifetime problems here: lifetime extension thanks to const only applies for local const references.

You need to make sure that the referenced function lives at least as long as the wrapper, or you need to copy/move the function into the wrapper.


but that gives an error due to the decaying of the function to a pointer

You can use std::decay_t<T> to ensure that you're copying/moving objects (e.g. closures) into the wrapper.

Vittorio Romeo
  • 90,666
  • 33
  • 258
  • 416