Reference data elements and move constructor
Assuming the following code:
class ChannelHandle;
class SessionHandle;
typedef ChannelHandle& ChannelHandleRef;
typedef SessionHandle& SessionHandleRef;
class RemoteChannelHandle
{
public:
RemoteChannelHandle(
ChannelHandleRef pChannelHandle, SessionHandleRef pSessionHandle);
RemoteChannelHandle(RemoteChannelHandle&&);
~RemoteChannelHandle();
void CloseChannel();
#ifndef _MSC_VER
RemoteChannelHandle& operator=(RemoteChannelHandle&&) = delete;
RemoteChannelHandle(RemoteChannelHandle const&) = delete;
RemoteChannelHandle& operator=(RemoteChannelHandle const&) = delete;
#endif
private:
LIBSSH2_CHANNEL* channel;
ChannelHandleRef channelHandle;
SessionHandleRef sessionHandle;
};
RemoteChannelHandle::RemoteChannelHandle(
ChannelHandleRef pChannelHandle, SessionHandleRef pSessionHandle)
: channel(nullptr), channelHandle(pChannelHandle), sessionHandle(pSessionHandle)
{
// OPEN SSH CHANNEL
}
RemoteChannelHandle::~RemoteChannelHandle()
{
try
{
CloseChannel();
}
catch (...)
{ }
}
void RemoteChannelHandle::CloseChannel()
{
if (channel == nullptr)
{
return;
}
// CLOSE SSH CHANNEL. THROW IF SOMETHING GOES WRONG
channel = nullptr;
}
- RemoteChannelHandle opens an SSH channel, but it takes two steps to clean up (close + free). The first step will be done in
~RemoteChannelHandle()
, but the second will be done in ChannelHandle dtor; hence the itemchannelHandle
, since we need to enterchannel
into it. This link can be fixed by following both steps in~RemoteChannelHandle()
. -
sessionHandle
contains theLIBSSH2_SESSION*
required SSH channel to open. Since I do not want to go throughLIBSSH2_SESSION*
, this link cannot be removed.
The problem comes when I define a ctor move for the RemoteChannelHandle. I need to clear the members of the "moved from" instance. However, there is no way to clear the link. So what do you do here?
- Use
(const) std::shared_ptr
instead of links? I could even use bare pointers as there is no property there. I understand that there is some debate regarding the use of references as data members, but other than moving the ctor, I see no other scenario where I would need to reset by handles (which is why I used references in the first place). - Leave the links as they are and create a state data item to check if the object is in a valid state (I can use it
channel != nullptr
for this purpose)? - Any other idea?
I've searched for alternatives to this and haven't found a clear answer. This could mean that there isn't really a clear answer, of course.
Thank you for your time.
Edit (in response to Mankarse): ChannelHandle only exists to do step 2 cleanup. Here's a simplified definition:
class ChannelHandle
{
public:
ChannelHandle();
ChannelHandle(ChannelHandle&&);
~ChannelHandle();
#ifndef _MSC_VER
ChannelHandle& operator=(ChannelHandle&&) = delete;
ChannelHandle(ChannelHandle const&) = delete;
ChannelHandle& operator=(ChannelHandle const&) = delete;
#endif
LIBSSH2_CHANNEL* GetChannel() { return channel; }
void SetChannel(LIBSSH2_CHANNEL* pChannel) { channel = pChannel; }
void FreeChannel();
private:
LIBSSH2_CHANNEL* channel;
};
SessionHandle is a RAII encapsulation for LIBSSH2_SESSION*
. It calls libssh2_session_init()
on ctor and libssh2_session_free()
dtor. Other similar classes will take care of the other steps of initializing / clearing the SSH session, but here we get LIBSSH2_SESSION*
from libssh2 and SessionHandle belongs to it. Once again, a simplified definition:
class SessionHandle
{
public:
SessionHandle();
SessionHandle(SessionHandle&&);
~SessionHandle();
void CloseSession();
LIBSSH2_SESSION* GetSession() { return session; }
#ifndef _MSC_VER
SessionHandle& operator=(SessionHandle&&) = delete;
SessionHandle(SessionHandle const&) = delete;
SessionHandle& operator=(SessionHandle const&) = delete;
#endif
private:
LIBSSH2_SESSION *session;
};
source to share