移动语义和cv::Mat

8

Opencv的文档中提到,目前没有移动构造函数,因此类似于cv::Mat A=std::move(some_other_cv_mat)这样的语句并没有太多意义。我的当前(并且是天真的)解决方案是从cv::Mat派生一个类,并实现以下移动构造函数:

namespace cv
{
    //matrix object derived from cv::Mat
    class Mvbl_Mat final: public Mat 
    {
        public:
          //constructors
          Mvbl_Mat(){};
          Mvbl_Mat(int rows, int cols, int type, const Scalar   &s):Mat(rows, cols, type, s){}
         //destructor
         ~Mvbl_Mat(){};

          //move constructor
          Mvbl_Mat(Mvbl_Mat && other) noexcept
          {   
              this->data=other.data;
              other.data=nullptr;
           } 
          //move assignment operator
          Mvbl_Mat & operator=(Mvbl_Mat && other)
          {   
              this->data=other.data;
              other.data=nullptr;
              return *this; 
          }   
     };

}

虽然目前这在我面临的有限问题上是行之有效的,但显然存在许多限制,解决方案远非理想。那么,模拟cv::Mat的移动语义的最佳方法是什么?


如果您提供移动构造函数/赋值运算符,为什么还要专门化? - Holt
此外,对于cv::Mat来说,move意义不大,因为复制构造函数不会复制数据。而您的移动构造函数可能会破坏引用计数器。 - Holt
@Holt 您是正确的,没有必要进行专门化,这毫无意义。谢谢。 - Ash
4
@Holt 我不同意。即使是针对引用计数模型(如shared_ptr),move也非常有意义,甚至可以说更有意义。想象一下,你希望将一个Mat对象传递给一个函数,但在调用后自己不需要这个Mat对象了。如果没有move,你就必须一直保持对这个对象的引用(以及内存)直到函数返回。而有了move,你就有机会在这种情况下在函数内部重复使用内存。 - pwuertz
2个回答

9

不需要这样做。 cv::Mat的复制构造函数实际上并没有复制数据。它只是创建了一个引用,所有对象共享相同的数据。

cv::Mat::Mat(const Mat & m)

这是一个为方便提供的重载成员函数。它与上面的函数唯一的区别在于接受的参数不同。

参数

m 赋给构建矩阵的数组(全部或部分)。这些构造函数不会复制任何数据。相反,指向m数据或其子数组的头文件被构建并与之关联。如果有引用计数器,则会增加引用计数器。因此,当您修改使用此类构造函数形成的矩阵时,也会修改m的相应元素。如果要拥有子数组的独立副本,请使用Mat :: clone()


1
是的,但我想在那之后能够销毁旧对象。使用复制构造函数,如果我删除旧对象,数据就会丢失,不是吗? - Ash
@Ash,“destroy”是什么意思?cv::Mat有一个引用计数,因此只有当没有cv::Mat拥有它时,数据才会被销毁。 - Holt
1
@Ash 你不应该这样做,因为它是引用计数的。这只会减少引用计数。它的工作方式类似于 std::shared_ptr - NathanOliver
3
shared_ptr 这样的好的引用计数模型是支持 move 语义的。如果没有 move,你无法将最后一个引用传递给函数,必须无谓地保留它(以及内存)直到函数返回。 - pwuertz
2
@Ash 你的意思是将Mat内容移动并从源中分离出来吗? 也许这就是你要找的:`cv::Mat source = /*初始化*/ ;` `cv::Mat dest;` `cv::swap(source, dest);` - user1832484

5

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接