Search code examples
c++11closuresshared-ptrunique-ptrinitializer-list

Closure deleter in initializer list (C++0x) and compiler warning


I get a warning C4355: 'this' : used in base member initializer list from Visual C++ 2010:

I have a class holding a handle, and I want to automatically close the handle even if the ctor for the class fails (so its dtor is not called). However, I don't want to bother making a whole handle-wrapping class, and would rather hold it in a smart pointer. And so I wrote this:

foo.h
~~~~~
class Foo
{
    ...
    Log &_log;
    std::unique_ptr<void, std::function<void (void *)>> _handle;
    ...
}

foo.cpp
~~~~~~~
#include <windows.h>
Foo::Foo(Log &lg, ...) : _log(lg), ... _handle(nullptr, [&](void *h){ if (h) { if (!CloseHandle(h)) LOG(_log, "Could not close port: " << LastWinErr()); h = nullptr; } })
{
    HANDLE h(CreateFile( ...
    if (h == ...
    _handle.reset(h);
    ... // Bunch of other stuff that could potentially throw
}

Previously to the closure I was initializing _handle with something like _handle(nullptr, bind(PortDeleter, placeholders::_1, ref(_log))), but that requires a separate definition.

My questions: is the warning a concern for this specific instance? Either way, what is the detailed reason? Is there a trivial way to avoid it?


Solution

  • The short is, if you pass your this pointer around and it's used to access member functions or variables in the initializer list or in the destructor, Bad Things Happen™. If you know that isn't going to happen, then feel free to ignore the warning. Of course, it's also a good warning- if any of the functions or variables that you access in the destructor belong to the class, then this is unsafe, as you may be accessing them prior to their construction/after their destruction. The problem is not critical if you know your initialization/destruction orders, but generally a bad move as this makes maintenance rather fiddly at best. As you could capture the constructor parameter instead, I'd have to recommend that.