ZDF ZDF - 1 year ago 71
C++ Question

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;

Answer Source

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 {
  decltype(auto) operator()(Args&&...args)const {
    return std::invoke( pfunc, std::forward<Args>(args)... );

int main() {
  class D{};

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

  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 as C++17 doesn't 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.)