我需要一个对象的单一所有权,因为我需要能够按需销毁它(这有时是有意义的;在这种情况下,对象代表一个登录的会话,出于安全原因,用户想要关闭) 。我们称这个对象为session
。其他客户端对象保留对session
的引用,但当然,当客户端访问引用时它可能已经死亡。
我所追求的是一个'安全引用',它在原始对象被销毁时得到通知,并且优雅地报告(例外,布尔)到客户端,而不是段错误。
有这样的事吗?最好使用标准C ++ / Boost中提供的功能。优选C ++ 03。如果仅shared_ptr
没有延长weak_ptr
的生命周期,shared_ptr
与session
几乎就是我所追求的。我需要保证 session
已被销毁,而迷路shared_ptr
会阻止这种情况发生。
答案 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;
}