引用数据成员和移动构造函数

时间:2013-01-24 11:11:56

标签: c++ reference c++11 move-semantics

假设以下代码:

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打开SSH通道,但清理需要 两步(关闭+免费)。第一步是在 ~RemoteChannelHandle(),但第二次将在 ChannelHandle的dtor;因此,数据成员channelHandle 我们需要将channel注入其中。这个参考可能是 通过执行~RemoteChannelHandle()
  • 中的两个步骤来消除
  • sessionHandle包含打开SSH所需的LIBSSH2_SESSION* 渠道。因为我不想传递LIBSSH2_SESSION*,所以 参考不能消除。

当我为RemoteChannelHandle定义move ctor时会出现问题。我需要清除“移动”实例的成员。但是,没有办法清除参考。那么,在这做什么?

  1. 使用(const) std::shared_ptr代替参考?我甚至可以使用 裸指针,因为没有涉及所有权。我意识到有一些争论 关于使用引用作为数据成员,但除了 移动ctor,我预见没有其他情况我需要重新安装 句柄(这就是我首先使用引用的原因)。
  2. 保留引用,并创建“状态”数据成员 专门检查对象是否处于有效状态(我可以使用channel != nullptr 为此目的)?
  3. 还有其他想法吗?
  4. 我已经找到了替代方案,并没有找到明确的答案。当然,这可能意味着没有明确的答案。

    感谢您的时间。

    编辑(回复Mankarse): ChannelHandle仅用于执行清理步骤2。这是一个简化的定义:

    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是LIBSSH2_SESSION*的RAII封装。它在ctor上调用libssh2_session_init(),在dtor调用libssh2_session_free()。其他类似的类负责SSH会话的init / cleanup的其他步骤,但这是我们从libssh2获取LIBSSH2_SESSION*的地方,而SessionHandle拥有它。再一次,简化定义:

    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;
    };
    

1 个答案:

答案 0 :(得分:3)

你自己回答了这个问题:

  

我甚至可以使用裸指针,因为没有涉及所有权。

相关问题