假设以下代码:

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

  • 当我为 RemoteChannelHandle 定义一个 move 构造函数时,就会出现问题。我需要清除“move 自”实例的成员。但是,没有办法清除引用。那么,在这里做什么?
  • 使用 (const) std::shared_ptr 而不是引用?我什至可以用
    裸指针,因为不涉及所有权。我意识到有一些争论
    关于使用引用作为数据成员,但除了
    move ctor,我预计没有其他情况需要重新安装
    句柄(这就是我首先使用引用的原因)。
  • 保留引用原样,并创建一个“状态”数据成员
    专门检查对象是否处于有效状态(我可以使用 channel != nullptr以此目的)?
  • 还有其他想法吗?

  • 我已经寻找了替代方案,但没有找到明确的答案。当然,这可能意味着实际上没有明确的答案。

    谢谢你的时间。

    编辑(回复 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 session 的初始化/清理的其他步骤,但这是我们从 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;
    };
    

    最佳答案

    你自己回答了这个问题:

    关于c++ - 引用数据成员和 move 构造函数,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/14499935/

    10-12 13:07