简体   繁体   中英

What's the difference between using an Assignment Constructor vs. normal assignment here?

I've spent some time trying to understand some C++ code, and I have background in C and Java. The code in question used what looked to be shorthand of some kind that I didn't recognize or understand for some time. I know now that they were using assignment constructors to assign variables, something that doesn't exist in either.

Here is the example:

cv::Mat rgb(raw_h1 + raw_h2, raw_w1, CV_8UC3);

is roughly equivalent I found to:

cv::Mat rgb = cv::Mat(raw_h1 + raw_h2, raw_w1, CV_8UC3);

At first I didn't know what I was looking at, though through debugging I knew what the effects were.

Later on, we have similarly a new piece of code:

cv::Mat dst_roi = rgb(cv::Rect(0, 0, raw_w1, raw_h1));

which seems to be a shorthand to call cv::Mat constructor:

Mat(const Mat& m, const Rect& roi);

Which would make sense that a roughly equivalent statement would be:

cv::Mat dst_roi = cv::Mat(rgb, cv::Rect(0, 0, raw_w1, raw_h1));

In fact, replacing the former code with the latter introduces no compiler error, so I likely am onto something here.

What is this second shorthand called where you can call a constructor on an already declared object to use the object as a parameter in the constructor of the object class?

Why would you use this form of assignment constructor over the other method of assignment as I have displayed? Does it involve speed? Conciseness? Or something that I don't know myself?

If I'm incorrect on any of my assumptions, please do not be afraid to point that out, but at least on the first one, I've been able to test and verify that I am correct.

The conversion you have is not correct.

cv::Mat rgb(raw_h1 + raw_h2, raw_w1, CV_8UC3); // (1)
cv::Mat dst_roi = rgb(cv::Rect(0, 0, raw_w1, raw_h1)); // (2)

(2) actually calls cv::Mat::operator()(const Rect &) which returns a new cv::Mat .

Then you copy initialize it into dst_roi (calls the copy constructor , or with C++17 guaranteed copy elision, no copy at all).

A simple rule of thumb:

1: When you declare an object the constructor is called.

// Variable `rgb` declared.
// Thus constructor used.
cv::Mat rgb(raw_h1 + raw_h2, raw_w1, CV_8UC3);

Though this declaration looks like an assignment, it is still a construction.

// In the old days, this could have been a construction (of a temporary)
// followed by a copy construction into the `rgb` object (from the temporary)
//
// Even in the old days, the standard allowed for the optimization by
// elision of the copy construction and all (majority of) the compilers used to
// implement that optimization; so the standard was updated to require
// the elision. So this is now just a normal constructor.
cv::Mat rgb = cv::Mat(raw_h1 + raw_h2, raw_w1, CV_8UC3);

2: If it is not a declaration, then it is an assignment.

// You don't have any examples above.
//
// Here we have construction of a temporary object.
// Followed by assignment of that object to rgb.
rgb = cv::Mat(raw_h1 + raw_h2, raw_w1, CV_8UC3);

3: Anything that uses braces () on an object (not a type). Is not calling a constructor, but using the object like a functor (function like object).

// rgb is an object.
// So `rgb(......)` is a functor call.
// Which means the type `cv::Mat` must define the operator()
cv::Mat dst_roi = rgb(cv::Rect(0, 0, raw_w1, raw_h1));

As a side note: This is why I always define my types with an initial capital letter, while objects/functions always have an initial lowercase letter. This is so I can tell if it is a functor/function call vs an object construction.

   // Common conventions using initial capital letter for user defined types.
   auto a = abc(1,23);   // function/functor call.
   auto b = Abc(1,23);   // object creation.

It used to be that using the assignment form T var = T(a, b, c) would involve creating a T object, and then calling T's copy constructor to copy it into var; whereas the form T var(a, b, c) didn't require the copy.

These days (post-C++ 17), mandatory copy elision means the call to the copy constructor is removed, so there's no difference.

More here: https://en.cppreference.com/w/cpp/language/copy_elision

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM