2015-02-17 68 views
2

我正在學習如何編寫PHP擴展並遇到了一個問題,我一直無法在Interwebs上找到答案。我試圖從我的PHP擴展中使用C++類,儘管它似乎在CLI中工作,但valgrind會報告問題。PHP擴展 - 使用std :: string的全局類

我的全局如下:

ZEND_BEGIN_MODULE_GLOBALS(myext) 
    MyClass *myClass; 
ZEND_END_MODULE_GLOBALS(myext) 

這個類實例化作爲全球性的擴展如下:

static void myext_init_globals(zend_myext_globals *myext_globals TSRMLS_DC) 
{ 
    myext_globals->myClass = (MyClass*)pemalloc(sizeof(MyClass), 0); 
    MyClass *myClass = new (myext_globals->myClass) MyClass(); 
} 

,它是利用釋放:

static void myext_destroy_globals(zend_myext_globals *myext_globals TSRMLS_DC) 
{ 
    pefree(myext_globals->myClass, 0); 
} 

MyClass.h :

class MyClass 
{ 
    private: 
    std::string strSomeText; 

    public: 
    MyClass(); 
    ~MyClass(); 
}; 

MyClass.cpp:

MyClass::MyClass() 
{ 
    strSomeText = "ABC"; // <-- this causes valgrind errors! 
} 

我發現,如果我可以strSomeText靜態成員變量,然後Valgrind的報告沒有任何錯誤。此外,如果我嘗試在MyClass構造函數中分配內存,然後在MyClass析構函數中刪除或釋放它,valgrind會再次報告泄漏。

理想情況下,我希望能夠抓住「任何醇類」,只需使用它,而無需對其進行重大更改,只需將其作爲全球PHP擴展工作即可。我的問題是,你如何使用類似std :: string的東西的「通用」C++類,或者分配/取消分配的內存(在構造函數/析構函數或成員方法中) ?我發現,如果我在MyClass中包含php.h,然後使用emalloc/pemalloc分配內存,然後用efree和pefree取消分配內存,那麼事情就會起作用,並且valgrind沒有報告內存泄漏。但是,這並不理想。必須有一種方法來使用「通用」C++類(即,您不必重構爲PHP擴展友好的類)作爲全局PHP擴展(如上面的示例中所示)。

+0

你的問題是什麼? – 2015-02-17 21:44:15

+0

如果您的實例是手動釋放的,那麼您是否也必須手動調用析構函數?看到http://stackoverflow.com/questions/8918791/how-to-properly-free-the-memory-allocated-by-placement-new – didierc 2015-02-17 21:56:26

+0

@IrrationalPerson - 我的問題是:你如何使用std :: string在一個全球PHP擴展沒有泄漏內存?我嘗試了幾件事情,除了(在上面的例子中)使strSomeText變爲靜態的以外,沒有任何東西可以工作。另一個(可能相關的)問題是如何在用作PHP擴展全局的對象中分配和釋放內存。我知道PHP與處理內存的方式有關,我只知道必須有一種方法可以在PHP擴展中使用一個簡單的C++類作爲全局。 – 2015-02-17 21:56:52

回答

0

爲什麼要使用pemalloc/pefree?我沒有看到myClass的析構函數是如何被調用的?試試這個,不ZEND_END_MODULE_GLOBALS:

std::unique_ptr<MyClass> myClass; 


PHP_MINIT_FUNCTION(myext) 
{ 
    myClass = std::unique_ptr<MyClass> (new MyClass); 
} 

PHP_MSHUTDOWN_FUNCTION(myext) 
{ 
    myClass.reset(); 
} 

這是非常棘手的PHP模塊使用C++。如果錯誤或HTTP請求中斷,PHP函數調用永遠不會返回。這打破了異常和析構函數的調用。所以最好將C++代碼與PHP函數調用完全分開。保證在啓動和退出模塊時調用PHP_MINIT_FUNCTION和PHP_MSHUTDOWN_FUNCTION。 但是,作爲Apache模塊的PHP可以創建一個模塊的虛擬版本,並且只有在這之後纔是真正的版本。 PHP_MINIT_FUNCTION和PHP_MSHUTDOWN_FUNCTION被稱爲虛擬版本,所以你應該避免在這裏分配巨大的對象和/或做大量的磁盤讀寫操作等。