我对以下案件有点困惑。我有以下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对象?
答案 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
仍然构造并有效,直到父对象的范围结束。永远不会破坏pM
,pM
也不会保留任何数据。
但是,OpenCV增加了另一个间接维度。 cv::Mat
通过指针存储数据,以防止在不需要时复制,这是一种浅拷贝形式。它本身可以智能地管理堆上的数据,并在数据不再被任何其他cv::Mat
引用时删除数据。因此,即使堆栈上的cv::Mat
对象也包含堆上的一些数据,以及堆栈上的其他详细信息,例如pM
。不相关,但由于您对cv::Mat
及其数据的范围感到困惑,我添加了一些细节。
编辑:临时变量,移动和默认ctor感谢sp2danny