2017-02-18 41 views
1

我對以下案例有些困惑。我有以下C++類,代表一個RGB像素:C++類的成員對象:它應該在哪裏被銷燬?

class RgbColorVector 
    { 
     cv::Mat pM; 

    public: 
    RgbColorVector(unsigned int r,unsigned int g,unsigned int b) 
    { 
     pM = cv::Mat(3,1,CV_8UC1); 
     pM.at<unsigned char>(0,0) = r; 
     pM.at<unsigned char>(1,0) = g; 
     pM.at<unsigned char>(2,0) = b; 
} 


unsigned int getComponent(int c) 
{ 
    return (unsigned int)pM.at<unsigned char>(c,0); 
} 

在這裏,我使用OpenCV的墊對象保存一個RGB值。通常在這種情況下,我會使用cv :: Mat指針,並使用new運算符在構造函數中分配堆內存,然後使用delete將其釋放到析構函數中。在上面的例子中,我明確地調用了cv :: Mat的構造函數。我期望的是當RgbColorVector的構造函數退出時,cv :: Mat構造函數中分配的內存將被銷燬。但顯然情況並非如此:

void func() 
{ 
    RgbColorVector rgbVec(105,42,45); 
    int g = rgbVec.getComponent(1); 
    std::cout<<g<<std::endl; 
} 


int main(int argc, const char * argv[]) { 
    func(); 
    return 0; 
} 

在這裏,我得到的輸出42.我知道,「rgbVec」是本地(自動)變量,並在「功能」退出,其內容(類成員)將被銷燬。但是,我期望getComponent()調用將返回一個隨機值,因爲在cv :: Mat構造函數調用中分配的任何內存將在「rgbVec」構造函數返回後被銷燬。我在這裏有點困惑,在這種情況下內存分配機制究竟如何工作?是不是在RgbColorVector()構造函數的堆棧中分配cv :: Mat對象?

+1

我不明白你會期待什麼樣的行爲。你正在通過pM = cv :: Mat(3,1,CV_8UC1)使用cv :: Mat的複製構造函數;所以構造的對象在你的類成員變量中(如果類對象被銷燬,它將被銷燬),它在func()的末尾。另外,如果你確實會訪問釋放內存,則不會返回「隨機」值,而是返回內存中的值。如果內存仍然屬於你的程序並且沒有被覆蓋,你甚至可能會觀察到「正確」的值,如果你不小心釋放了內存。 – Micka

+1

使用Mat來存儲單個像素值的想法非常糟糕。你最好使用Vec3b,或者只使用3個UI – Miki

回答

4
class RgbColorVector 
{ 
    cv::Mat pM; // <- this object is valid as long 
       // as the parent is (value semantics) 

public: 
    RgbColorVector(unsigned int r,unsigned int g,unsigned int b) 
     // <- pM gets implicitly allocated here 
    { 
     pM = cv::Mat(3,1,CV_8UC1); // <- this creates a temporary, and 
            // assign its value to pM 

     // <- the temporary gets implicitly deallocated here. 
     // pM isn't affected. 

     pM.at<unsigned char>(0,0) = r; 
     pM.at<unsigned char>(1,0) = g; 
     pM.at<unsigned char>(2,0) = b; 
    } 
}; 

的正確方法來初始化成員是這樣的:

RgbColorVector(unsigned int r,unsigned int g,unsigned int b) 
     : pM(3,1,CV_8UC1) 
    { 

這就是所謂的成員初始化列表

+1

當使用cv :: Mat調用創建臨時對象時,它會在堆中分配內存以保存顏色值。臨時cv :: Mat的所有類成員與數據指針一起被複制到pM類成員中,因此堆上的像素數據仍然有效,對嗎? –

+0

'cv :: Mat'可能會或可能不會在內部使用堆,這取決於該類,並且應該對用戶沒有任何影響。 C++使用值語義,即類應該像'int'那樣工作,如果複製一個值,那麼在原始之後發生什麼並不重要,複製不受影響。 – sp2danny

+0

@BattleBeast這是正確的。它的作用類似於共享指針。 –

0

您正在致電cv::Mat副本,因此新創建的臨時文件cv::Mat已移至已構建的pM。因此,pM保持構造並有效直到父對象的作用域結束。 pM不會被破壞,也不會被pM持有。

但是,OpenCV增加了間接性的另一個維度。 cv::Mat通過指針存儲數據,以防止在不需要時進行重複,這是一種淺拷貝形式。它本身巧妙地管理堆上的數據,並在數據不再被任何其他cv::Mat引用時刪除數據。因此,堆棧上的一個對象cv::Mat包含堆上的一些數據以及堆棧上的其他詳細信息,這與您的pM一樣。不相關,但由於您對cv::Mat及其數據的範圍感到困惑,因此我添加了一些細節。

編輯:臨時變量,移動和默認構造函數感謝sp2danny

+2

它不是被調用的複製構造函數,首先隱式調用默認構造函數,然後調用臨時get的顯式構造,然後移動賦值 – sp2danny

+0

...它可以通過使用pM的構造函數中的初始化程序列表進行糾正http://en.cppreference.com/w/cpp/language/initializer_list – xaxxon