9

This example compiles and runs well with gcc 4.8.3:

#include <memory> #include <functional> #include <iostream> int main() { auto str = new const char[6]{'h', 'e', 'l', 'l', 'o', '\0'}; std::unique_ptr<const char[], std::function<void(const char *)>> u_ptr(str, [](const char *s){ delete[] s; }); std::cout << u_ptr.get() << std::endl; } 

But when I try it with Visual Studio Professional 2013 it doesn't compile (complains about a deleted function). Is this not yet possible with Visual Studio 2013? Or is my sample code wrong and gcc ignores my mistake?

Error is:

main.cpp(8) : error C2280: 'std::unique_ptr>::unique_ptr>(_Ptr2,_Dx2)' : attempting to reference a deleted function with [ _Ptr2=const char * , _Dx2=main:: ] C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\INCLUDE\memory(16 16) : see declaration of 'std::unique_ptr>::unique_ptr'

9
  • 3
    There should be a FAQ on "why is using std::function as a unique_ptr deleter a terrible idea?" Commented Jun 1, 2015 at 16:32
  • 1
    Shouldn't T be char instead of char const[]? This works on Visual C++ 2015 RC. Commented Jun 1, 2015 at 16:33
  • 4
    std::unique_ptr already supports delete[] there is no reason to write your own here. Commented Jun 1, 2015 at 16:36
  • 2
    @T.C.: Can you elaborate or give some link about why is that a bad idea? Commented Jun 1, 2015 at 16:42
  • 3
    @rodrigo Exceptions. unique_ptr requires that all operations associated with its deleter must not throw; std::function's constructors can throw, because it uses type erasure and may need to allocate memory under the hood. (In the OP's code it's even worse, because the std::function would be constructed before unique_ptr's constructor is called, and if that throws then the pointer is leaked regardless of what unique_ptr requires.) Commented Jun 1, 2015 at 18:03

1 Answer 1

6

This appears to be a defect in the Visual C++ 2013 standard library. I cannot reproduce the problem on 2015.

The unique_ptr class has this constructor for taking a pointer and a deleter:

unique_ptr(pointer _Ptr, typename _If<is_reference<_Dx>::value, _Dx, const typename remove_reference<_Dx>::type&>::type _Dt) _NOEXCEPT : _Mybase(_Ptr, _Dt) { // construct with pointer and (maybe const) deleter& } 

However, the unique_ptr<T[]> specialization also has a catch-all constructor:

template<class _Ptr2, class _Dx2> unique_ptr(_Ptr2, _Dx2) = delete; 

This version is preferred over the previous one.

However, because the non-specialized unique_ptr doesn't have it at all, changing u_ptr to a const char instead of const char[] fixes the problem.

Using the array version with a deleter like you're doing is also unnecessary:

  1. If you want to call delete[] on your pointer, there's already a specialization for arrays. You don't need a custom deleter.

  2. If you want to do something else, you should use the non-specialized version.

Sign up to request clarification or add additional context in comments.

2 Comments

as I mentioned in my comment on the question std::unique_ptr<T[]> is already provided. There is no need for a custom deleter here.
@Mgetz the OP is asking if his code is syntactically correct (And why the compilers disagree). The existence of an already suitable deleter is irrelevant, as he provided a MCVE and he may need, in the actual real problem, to use a custom deleter.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.