Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lambda Deleter in VC 2013 vs 2015

I am moving some old code from VC 2013 to 2015.

The simplified code below works fine in VC 2013, but fails in 2015 with:

error C2664: 'void main::<lambda_da721648e605a5fd45c9a3fb8c3d06f6>::operator ()(main::D *&) const': cannot convert argument 1 from 'main::D *' to 'main::D *&'

I am not looking for a solution, but for an explanation on what and why changed.


Thank you.

#include <memory>

int main()
{
  class D{};

  auto mydel = []( D*&p ) { delete p; p = 0; };

  std::unique_ptr< D, decltype(mydel) > up( new D );

  return 0;
}
like image 856
zdf Avatar asked Feb 07 '23 08:02

zdf


1 Answers

The type of deleter must be callable with an argument of type pointer. In your case pointer is D*. Your deleter is not callable with this, but instead requires an argument of type pointer&, so your code was ill-formed with no diagnostic required.

In addition, decltype(mydel) is a lambda object type. Lambda objects have no default constructor, even stateless ones. Your unique pointer creating code:

std::unique_ptr< D, decltype(mydel) > up( new D );

is thus ill-formed. The correct verson would be:

std::unique_ptr< D, decltype(mydel) > up( new D, mydel );

This is annoying.

Odds are 2013's lambda had a zero argument constructor lying around, in violation of the standard. MSVC2013 was only nominally a C++11 compiler.

In addition, it probably only passed in lvalue D* types. It is permitted to do this, but it is not required to do it by the standard.


While this is not the focus of your question, I will note we can clean this up in C++17 as follows:

template<auto* pfunc>
struct stateless {
  template<class...Args>
  decltype(auto) operator()(Args&&...args)const {
    return std::invoke( pfunc, std::forward<Args>(args)... );
  }
};

int main() {
  class D{};

  auto mydel = []( D*p ) { delete p; };

  std::unique_ptr< D, stateless<+mydel> > up( new D );

  return 0;
}

but MSVC2015 doesn't support this (maybe if you requested the latest standard in a later update it might).

C++17 code not tested on a C++17 compiler, as none actually exist yet (There are some C++1z compilers, and some might actually be able to compile the above, but I don't have them lying around.)

like image 149
Yakk - Adam Nevraumont Avatar answered Feb 23 '23 18:02

Yakk - Adam Nevraumont