move semantics and cv::Mat
Asked Answered
S

2

8

Opencv's documentation on cv::Mat seems to indicate that there are no move constructors at the moment, so something like cv::Mat A=std::move(some_other_cv_mat) doesn't make much sense. My current (and naïve) solution to this problem is to derive a class from cv::Mat, for which I implement a move constructor as follows:

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; 
          }   
     };

}

While this works for the limited problems that I face at the moment, there are obviously many limitations and the solution is far from ideal. So, what is the best way to emulate move semantics for cv::Mat?

Strade answered 24/5, 2018 at 13:21 Comment(4)
Why do you specialize if you provide move constructor/assignment?Earphone
Also, move does not make much sense for cv::Mat because the copy constructor does not copy the data. And your move constructor probably breaks the reference counter.Earphone
@Earphone You are right, there is no need to specialize it, it makes no sense. Thanks.Strade
@Earphone I disagree. move makes a lot of sense, even, or especially for a refcount model (see shared_ptr). Imagine you'd like to pass a Mat into a function but you don't need the Mat for yourself after the call. Without move you are forced to hold on to your reference (and the memory) until the function returns. With move you have the opportunity to reuse memory within the function in such cases.Ruse
W
9

There is no need to do this. cv::Mat's copy constructor doesn't actually copy the data. It basically makes a reference and all objects share the same data.

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

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

Parameters

m Array that (as a whole or partly) is assigned to the constructed matrix. No data is copied by these constructors. Instead, the header pointing to m data or its sub-array is constructed and associated with it. The reference counter, if any, is incremented. So, when you modify the matrix formed using such a constructor, you also modify the corresponding elements of m . If you want to have an independent copy of the sub-array, use Mat::clone()

Wilsey answered 24/5, 2018 at 13:29 Comment(5)
Yes, but I want to be able to destroy the older object after that. With the copy constructor, I will lose the data if I delete the older object, no?Strade
@Strade What do you mean by "destroy"? cv::Mat has a reference count, so the data will only get destroyed when no cv::Mat owns it.Earphone
@Strade You shouldn't since it is reference counted. It would just decrees the reference count. It works like std::shared_ptrWilsey
@Wilsey A good refcount model like shared_ptr DOES support move semantics. Without move you can't pass your last reference into a function, you are forced to hold on to it (and the memory) unnecessarily until the function returns.Ruse
@Strade you mean move Mat content and detach from source? Maybe this is what you're looking for cv::Mat source = /*initialization*/ ; cv::Mat dest; cv::swap(source, dest);Sacculate
F
6

As of 4.x OpenCV provides Mat (Mat &&m) and Mat & operator= (Mat &&m).

If you are working on a version prior to 4.x, I'd suggest to take a look at the cv::Mat move constructor and move assignment operator implementations defined in modules/core/include/opencv2/core/mat.inl.hpp, as it's a little more complicated that just copying the .data member.

Follow answered 15/4, 2020 at 13:49 Comment(3)
Even in OpenCV 4.9.0, Mat(Mat&&) is noexcept(false), so it gets the vector pessimization and folly::fbvector<cv::Mat> doesn't compile at all (folly#1821). Any idea why the move constructor can't be noexcept? (And/or, to the people reading this in the future: When willen-have-been noexcept added to the move constructor?)Insult
@Insult I guess it was simply a lack of the early implementation. It is currently declared as CV_NOEXCEPT: github.com/opencv/opencv/blob/4.x/modules/core/src/…Follow
@ Sdra: Yep, that CV_NOEXCEPT was added in github.com/opencv/opencv/pull/25899 in response to my bug report of Feb 21. :)Insult

© 2022 - 2024 — McMap. All rights reserved.