确保对象的数据一致性

时间:2013-09-24 06:36:59

标签: boost-python

我遇到了对象的数据一致性问题,例如如何处理在用户仍然引用它们时被删除的对象。

简单的伪代码示例

node = graph.getNode(name)

node.destroy() < -- node gets destroyed
#or
graph.destroyNode(name)

node.getName() #<-- should complain that we're trying to reference an object that does not exist any more

一个简单的伪代码示例是

struct Node
{
   /*...*/
};
typedef boost::shared_ptr<Node> NodePtr;

struct Graph
{
   std::map<std::string,NodePtr> nodeMap;

   NodePtr getNode(std::string name);
   void removeNode(std::string name);  
   /*...*/
};
typedef boost::shared_ptr<Graph> GraphPtr;

// wrapper arround the the getNode function
object Graph_getNode( object obj, const std::string& key )
{
     GraphPtr graphPtr = extract< GraphPtr >(obj);
     return boost::python::api::object(graphPtr->getNode(key));
};

class_< Node,boost::noncopyable, NodePtr >( "Node", "node", no_init )
    /*....*/

class_< Graph, bases<Node>, boost::noncopyable, GraphPtr >( "Graph", "graph", no_init )
    .def("getNode", Graph_getNode, "get a node if it exists")
    /*....*/

我是否可以定义哪些函数在每次使用时都在Node-object上运行,我可以检查它是否仍然有效?

我希望这些信息足以理解我的问题,  ...感谢阅读!

的Seb

1 个答案:

答案 0 :(得分:0)

Nodeboost::shared_ptr公开时,实例的生命周期可能会受到C ++和Python的影响。只要存在Node的Python对象的句柄,Python就会使C ++ boost::shared_ptr对象保持活动状态。

因此,在以下代码中,让我们从Node中保存名为spam graph的前提条件开始。代码注释了C ++ Node实例的引用计数,以及Python Node实例。

# The node named 'spam' is held in
# graph's nodeMap.
# cpp count: 1; python count: 0

# Boost.Python creats a Python Node object
# that holds boost::shared_ptr<Node>.
node = graph.getNode('spam') # cpp count: 2; python count: 1

# Removes the boost::shared_ptr<Node> for
# 'spam' from graph.nodeMap.
graph.destroyNode('spam') # cpp count: 1; python count: 1

# The C++ Node is still alive because the
# Python Node holds a boost::shared_ptr<Node>
node.getName() # cpp count: 1; python count: 1

# When Python no longer has a handle to the
# Python Node object, it will be garbage
# collected, which in turn will destroy
# the held boost::shared_ptr<Node>
node = None # cpp count: 0; python count: 0

如果node.getName()无法在已销毁的node上成功运行,请考虑明确管理状态。例如,node.destroy()将在node内设置状态,成员函数将在执行操作之前检查状态。如果状态指示node已被销毁,则引发异常或正确处理它。


以下是演示生命周期的基本示例:

#include <map>
#include <string>
#include <boost/make_shared.hpp>
#include <boost/python.hpp>
#include <boost/shared_ptr.hpp>

class Node
{
public:
  Node(std::string name)
    : name_(name)
  {
    std::cout << "Node()" << std::endl;
  }

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

  std::string name() { return name_; }

private:
  std::string name_;
};

class Graph
{
public:
  // @brief Add node by name.
  void add_node(std::string name)
  {
    nodes_.insert(make_pair(name, boost::make_shared<Node>(name)));
  }

  /// @brief Destroy node by name.
  void destroy_node(std::string name)
  {
    nodes_.erase(name);
  }

  // @brief Get node by name.
  boost::shared_ptr<Node> get_node(std::string name)
  {
    nodes_type::iterator result = nodes_.find(name);
    return (result != nodes_.end())
      ? result->second
      : boost::shared_ptr<Node>();
  }

private:
  typedef std::map<std::string, boost::shared_ptr<Node> > nodes_type;
  nodes_type nodes_;
};

BOOST_PYTHON_MODULE(example)
{
  namespace python = boost::python;

  python::class_<Node, boost::shared_ptr<Node>, 
      boost::noncopyable>("Node", python::no_init)
    .def("name", &Node::name)
    ;

  python::class_<Graph, boost::noncopyable>("Graph")
    .def("add_node",     &Graph::add_node)
    .def("get_node",     &Graph::get_node)
    .def("destroy_node", &Graph::destroy_node)
    ;
}

它在Python中的用法:

>>> from example import Graph
>>> graph = Graph()
>>> graph.add_node('spam')
Node()
>>> node = graph.get_node('spam')
>>> print node.name()
spam
>>> graph.destroy_node('spam')
>>> print node.name()
spam
>>> graph = None
>>> node = None
~Node()

注意只有在Python不再拥有对象句柄时才会调用Node的析构函数。