I have a base class that basically wraps up attaching a class to a arbitrary windows handle (e.g, HWND, HFONT), and uses a policy class to attach/detach and destroy:
// class SmartHandle
template<typename THANDLE, class TWRAPPER, class TPOLICY>
class SmartHandle : boost::noncopyable
{
private:
TPOLICY* m_pPolicy; // Policy
bool m_bIsTemporary; // Is this a temporary window?
SmartHandle(); // no default ctor
SmartHandle(const SmartHandle<THANDLE, TWRAPPER, TPOLICY>&); // no cctor
protected:
THANDLE m_hHandle; // Handle to the underlying window
TPOLICY& policy() {return(*m_pPolicy);};
// ctor that attaches but is temporary
SmartHandle(const THANDLE& _handle, bool _temporary) : m_hHandle(_handle)
, m_bIsTemporary(_temporary)
{
m_pPolicy = new TPOLICY(reinterpret_cast<TWRAPPER&>(*this));
if(_handle)
m_pPolicy->attach(_handle);
}; // eo ctor
// move ctor
SmartHandle(SmartHandle<THANDLE, TWRAPPER, TPOLICY>&& _rhs) : m_hHandle(_rhs.m_hHandle)
, m_bIsTemporary(_rhs.m_bIsTemporary)
{
m_pPolicy = new TPOLICY(reinterpret_cast<TWRAPPER&>(*this));
m_pPolicy->attach(m_hHandle);
const_cast<SmartHandle&>(_rhs).m_hHandle = NULL;
}; // eo mtor
// dtor
virtual ~SmartHandle()
{
if(m_hHandle)
{
m_pPolicy->detach(m_hHandle);
if(!m_bIsTemporary)
m_pPolicy->destroy(m_hHandle);
m_hHandle = NULL;
};
delete(m_pPolicy);
m_pPolicy = NULL;
}; // eo dtor
Note that I've declared the copy constructor private (with no implementation) as I do not want the class to be copied, but a move is allowed.
My Window
class derives from this:
class GALLOW_API Window : SmartHandle<HWND, Window, detail::_hWndPolicy>
{
friend class Application;
private:
static LRESULT CALLBACK wndProc(HWND _hWnd, UINT _message, WPARAM _wParam, LPARAM _lParam);
// no copy/default ctor
Window();
Window(const Window&);
protected:
public:
static const String ClassName;
Window(const HWND& _hWnd);
Window(const WindowCreateInfo& _createInfo);
Window(Window&& _rhs);
virtual ~Window();
}; // eo class Window
Once again, copy default/copy ctors. The implementation of the move constructor is:
Window::Window(Window&& _rhs) : SmartHandle(_rhs)
{
}; // eo mtor
However, during compilation I get the following error on the first line of the move constructor implementation:
1>c:\\documents\visual studio 2010\projects\gallow\gallow\window.cpp(81): error C2248: 'gallow::SmartHandle<THANDLE,TWRAPPER,TPOLICY>::SmartHandle' : cannot access private member declared in class 'gallow::SmartHandle<THANDLE,TWRAPPER,TPOLICY>'
So, it appears as if it is trying to call the copy constructor (which I've declared private) rather than the move constructor. Is there something simple I am missing here?
Thanks in advance.
EDIT: Modified mtor so it was non-const, error remains. EDIT2: I am using Visual C++ 2010.
A move constructor in general does not have to provide default initialization. Your move constructor does. A move constructor is still a constructor. And therefore, it must initialize all subobjects.
A move constructor allows the resources owned by an rvalue object to be moved into an lvalue without creating its copy. An rvalue is an expression that does not have any memory address, and an lvalue is an expression with a memory address.
std::move is actually just a request to move and if the type of the object has not a move constructor/assign-operator defined or generated the move operation will fall back to a copy.
The move assignment operator is different than a move constructor because a move assignment operator is called on an existing object, while a move constructor is called on an object created by the operation. Thereafter, the other object's data is no longer valid.
actually it should be like this.
Window::Window(Window&& _rhs) : SmartHandle( std::forward<SmartHandle>( _rhs ) ) { }; // eo mtor
http://msdn.microsoft.com/en-us/library/ee390914.aspx
A named argument isn't treated as a rvalue reference you have to move
it.
Window::Window(Window&& _rhs) : SmartHandle(std::move(_rhs))
{
}
The reason an argument isn't treated as an rvalue is that it can be used twice and moving typically changes the value therefore you have to be explicit about knowing that this variable is moved from.
e.g.
void f(string&& first, string&& second)
{
string local = first;
cout << first; // I would be surprised if this is different from `local`
local = std::move(second);
// If I'm surprised after explicitly moving from second it's my problem
}
It's better to use move
rather than forward
in cases when you want to move since a) it's clearer and b) you need to specify a type for forward
which is verbose and error prone.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With