2016-07-06 142 views
2

當包裝對象的C++析構函數被調用時,考慮到達對應python對象的引用計數0的時刻,boost :: python會提供任何保證嗎?boost :: python包裝對象的C++析構函數調用

我很關心一個C++對象,它打開一個用於寫入的文件並在其析構函數中執行文件關閉。當所有對該對象的python引用被刪除或超出範圍時,它是否保證寫入文件?

我的意思是:

A=MyBoostPythonObject() 
del A # Is the C++ destructor of MyBoostPythonObject called here? 

我的經驗表明,析構函數總是被調用在這一點上卻找不到任何保證。

+0

這是否有什麼關係與一個活躍的對象?如果是這樣,你可以閱讀:https://msdn.microsoft.com/en-us/library/windows/desktop/ms221551%28v=vs.85%29.aspx – 2016-07-06 19:12:43

回答

3

Boost.Python保證如果Python對象擁有包裝的C++對象的所有權,那麼當Python對象被刪除時,被包裝的C++對象將被刪除。 Python對象的生命週期由Python規定,其中當對象的引用計數達到零時,可立即銷燬對象。對於非簡單的情況,例如循環引用,對象將由垃圾回收器進行管理,並且在程序退出之前可以銷燬10或

一個Pythonic解決方案可能是暴露一個類型,實現context manager protocol。內容管理器協議由一對方法組成:一個在進入運行時上下文時被調用,另一個在退出運行時上下文時被調用。通過使用上下文管理器,可以控制文件打開的範圍。

>>> with MyBoostPythonObject() as A: # opens file. 
...  A.write(...)     # file remains open while in scope. 
...         # A destroyed once context's scope is exited. 

這裏是暴露RAII型類Python作爲一個上下文管理器的示例demonstrating

#include <boost/python.hpp> 
#include <iostream> 

// Legacy API. 
struct spam 
{ 
    spam(int x) { std::cout << "spam(): " << x << std::endl; } 
    ~spam()  { std::cout << "~spam()" << std::endl;   } 
    void perform() { std::cout << "spam::perform()" << std::endl; } 
}; 

/// @brief Python Context Manager for the Spam class. 
class spam_context_manager 
{ 
public: 

    spam_context_manager(int x): x_(x) {} 

    void perform() { return impl_->perform(); } 

// context manager protocol 
public: 

    // Use a static member function to get a handle to the self Python 
    // object. 
    static boost::python::object enter(boost::python::object self) 
    { 
    namespace python = boost::python; 
    spam_context_manager& myself = 
     python::extract<spam_context_manager&>(self); 

    // Construct the RAII object. 
    myself.impl_ = std::make_shared<spam>(myself.x_); 

    // Return this object, allowing caller to invoke other 
    // methods exposed on this class. 
    return self; 
    } 

    bool exit(boost::python::object type, 
      boost::python::object value, 
      boost::python::object traceback) 
    { 
    // Destroy the RAII object. 
    impl_.reset(); 
    return false; // Do not suppress the exception. 
    } 
private: 
    std::shared_ptr<spam> impl_; 
    int x_; 
}; 


BOOST_PYTHON_MODULE(example) 
{ 
    namespace python = boost::python; 
    python::class_<spam_context_manager>("Spam", python::init<int>()) 
    .def("perform", &spam_context_manager::perform) 
    .def("__enter__", &spam_context_manager::enter) 
    .def("__exit__", &spam_context_manager::exit) 
    ; 
} 

互動用法:

>>> import example 
>>> with example.Spam(42) as spam: 
...  spam.perform() 
... 
spam(): 42 
spam::perform() 
~spam() 
+0

有沒有一種很好的方法來阻止用戶只是做:'垃圾郵件= example.Spam(42)'和無意中泄漏? –

+0

@ SamKellett考慮使用RAII類來管理底層資源,並將資源獲取推遲到'__enter__'而不是類構造函數。在上面的例子中,底層資源只在'Spam .__輸入__()'中獲得,並且當使用'std :: shared_ptr'時,資源在'Spam .__ exit__'中顯式釋放,或者當Python銷燬垃圾郵件時對象。 –

+0

但這不會阻止用戶能夠做'spam = example.Spam(42)',是嗎?它不會給他們一個懸而未決的參考/ nullptr? –

相關問題