C ++中的安全引用(带有通知语义的单一所有权指针)

时间:2013-12-04 11:21:48

标签: c++ reference smart-pointers

我需要一个对象的单一所有权,因为我需要能够按需销毁它(这有时是有意义的;在这种情况下,对象代表一个登录的会话,出于安全原因,用户想要关闭) 。我们称这个对象为session。其他客户端对象保留对session的引用,但当然,当客户端访问引用时它可能已经死亡。

我所追求的是一个'安全引用',它在原始对象被销毁时得到通知,并且优雅地报告(例外,布尔)到客户端,而不是段错误。

有这样的事吗?最好使用标准C ++ / Boost中提供的功能。优选C ++ 03。如果仅shared_ptr没有延长weak_ptr的生命周期,shared_ptrsession几乎就是我所追求的。我需要保证 session已被销毁,而迷路shared_ptr会阻止这种情况发生。

4 个答案:

答案 0 :(得分:3)

您要求的设计存在根本问题。

假设您有会话和会话的用户。用户检查会话是否有效,然后使用它。同时,在检查和使用之间会话变得无效。 weak_ptr通过允许用户升级到shared_ptr来处理此问题,然后检查并使用它。你的设计排除了这一点。

如果你愿意忽略这个问题,我有一个解决方案。

该对象将shared_ptr<void>(分配为char)作为成员保留。它公开weak_ptr<void>,可用于跟踪其生命周期,但不确定它。对象本身存储unique_ptr,用户保留原始指针和生命跟踪器对。

这不会立即更新终止终止:对于那个使用回调模式。

答案 1 :(得分:1)

可能是这样的:

class Session
{
    private:
    class Implementation {};

    public:
    Session()
    :   m_self(0) // You might do better, here
    {}

    ~Session() { delete m_self; }

    private:
    Session(const Session&); // No copy
    Session& operator = (const Session&); // No copy

    public:
    bool valid() const { return bool(m_self); }
    void terminate() { delete m_self; m_self = 0; }

    private:
    Implementation* m_self;
};

上面的类与std :: shared_ptr或std :: unique_ptr没有相似之处。每个会话对象只能通过引用传递。

如果您需要发出会话终止(或其他事件)的信号,我建议将boost :: signal2放入实现中。

答案 2 :(得分:0)

Session类包含在SharedSession中,它只有一个Session参考。 SharedSession类为客户端提供Session类的行为。客户端可以在尝试访问会话时关闭会话和所有其他引用获取异常。 此代码示例中未涉及锁定线程的情况。

#include<iostream>
#include<utility>

//- single object ownership
//- ensure shared object is not deleted by one of the reference deletion;
//- client should be notified when pointed memory is deleted explicitly on request.

//Proxy class for Session
class SharedSession{

  //Session class
  class Session{

    public:

      Session()
      {
        std::cout<<"Session ctr"<<std::endl;
      }

      bool isValidSession()
      {
        std::cout<<"Is valid session"<<std::endl;
      }

      bool login(std::string user,std::string password,std::string& sessionId)
      {
        std::cout<<"Login session"<<std::endl;
        //authenticate user - password and generate session id.
        sessionId = "abd123";
        return true;
        //return false //in case of failure
      }

      ~Session()
      {
        std::cout<<"Session dtr"<<std::endl;
      }


    private:

      std::string _userName;
      std::string _password;
      std::string _sessionId;

      Session(const Session& rhs){}
      Session& operator=(const Session& rhs){}
  };

  Session* _sessionInstance;
  //number of SharedSession objects created
  static int _sessionCount;
  //single ownership of sesion maintained in pair
  static std::pair<int,Session*> _sessionPair;
  //maintain state of session 
  static std::pair<bool,int> _sessionValid;

  public:

  SharedSession()
  {
    ++_sessionCount;
    std::cout<<"Shared Session "<<_sessionCount<<std::endl;
    if(_sessionCount == 1)
    {
      _sessionInstance = new Session();
      _sessionPair = std::make_pair(1,_sessionInstance);
      _sessionValid = std::make_pair(true,_sessionCount);
    }
    if(!_sessionValid.first)
      throw -1;//session is deleted
    else
    {
      _sessionValid.second = _sessionCount;
      _sessionInstance = NULL;
    }
  }

  ~SharedSession()
  { 
    std::cout<<"Shared session dtr  "<<_sessionValid.second<<std::endl;
    if(_sessionValid.second == 1 && _sessionValid.first)
    {
      delete (_sessionPair.second);
      std::cout<<"session deleted"<<std::endl;
      _sessionPair.second = NULL;
      _sessionValid.first = false;
    }
    _sessionValid.second -= 1;
    --_sessionCount;
  }

  bool closeSession()
  {
    //invalidate session
    _sessionValid.first = false;
    std::cout<<"close session"<<std::endl;
    delete _sessionPair.second;
  }

  bool isValidSession()
  {
    std::cout<<"session state "<<_sessionValid.first<<std::endl;
    if(_sessionValid.first)
      _sessionPair.second->isValidSession();
    else
      //notify client about deleted session
      throw -1;
  }

  bool login(std::string user,std::string password,std::string& sessionId)
  {
    if(_sessionValid.first)
      return _sessionPair.second->login(user,password,sessionId);
      //notify client about deleted session
    throw -1;
  }

  //any other operations which Session class exposes
};

int SharedSession::_sessionCount = 0;
std::pair<int,SharedSession::Session*> SharedSession::_sessionPair;
std::pair<bool,int> SharedSession::_sessionValid;

int main()
{
  SharedSession session1;
  SharedSession session2;
  try
  {
    session1.closeSession();
    session2.isValidSession();
  }
  catch(int& error)
  {
    std::cout<<"Exception occured  "<<error<<std::endl;
    std::cout<<"Session already deleted."<<std::endl;
  }
  return 0;
}

答案 3 :(得分:-1)

这样的事情:

#include <assert.h>

template <class T>
class notify_ptr
{
public:
    notify_ptr(T* ptr):m_ptr(ptr){};
    void kill()
    {
        if (m_ptr)
        {
            delete m_ptr;
            m_ptr = 0;
        }
    }
    bool isAlive()
    {
        return m_ptr!=0;
    }   
    T* operator->()
    {
        if (!m_ptr)
        {
            assert("Using a dead reference !");
            return 0; // segfault
        }
        return m_ptr;
    }
private:
    T* m_ptr;
};

class session
{
public:
    session():i(0){}
    void AddOne(){++i;}
private:
    int i;
};

void bar(notify_ptr<session>& mySession)
{
    mySession->AddOne();
    mySession.kill();
}

int main()
{
    notify_ptr<session> ptr(new session);
    bar(ptr);
    if (ptr.isAlive())
    {
        ptr->AddOne();
    }
    return 0;
}