C ++类的成员对象:它应该在哪里销毁?

时间:2017-02-18 09:53:01

标签: c++ opencv memory-management constructor

我对以下案件有点困惑。我有以下C ++类,表示RGB像素:

  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 Mat对象来保存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”是一个本地(自动)变量,当“func”退出时,其内容(类成员)将被销毁。但是,我预计getComponent()调用将返回一个随机值,因为在“rgbVec”构造函数返回后,cv :: Mat构造函数调用中分配的任何内存都将被销毁。我在这里有点困惑,在这种情况下内存分配机制究竟是如何工作的?是不是在RgbColorVector()构造函数的堆栈上分配了cv :: Mat对象?

2 个答案:

答案 0 :(得分: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 :(得分:0)

您正在调用cv::Mat副本ctor,因此新创建的临时cv::Mat将移至已构建的pM。因此,pM仍然构造并有效,直到父对象的范围结束。永远不会破坏pMpM也不会保留任何数据。

但是,OpenCV增加了另一个间接维度。 cv::Mat通过指针存储数据,以防止在不需要时复制,这是一种浅拷贝形式。它本身可以智能地管理堆上的数据,并在数据不再被任何其他cv::Mat引用时删除数据。因此,即使堆栈上的cv::Mat对象也包含堆上的一些数据,以及堆栈上的其他详细信息,例如pM。不相关,但由于您对cv::Mat及其数据的范围感到困惑,我添加了一些细节。

编辑:临时变量,移动和默认ctor感谢sp2danny