1

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.

Chthonic One
  • 213
  • 3
  • 11
  • 4
    C++ doesn't have an "assignment constructor". The variant you use with initialization using `=` a *copy* constructor. – Some programmer dude Jan 26 '23 at 17:36
  • 5
    The difference is that the copy constructor is a constructor, and the assignment operator is an assignment. A constructor creates a new object; assignment modifies an existing object. – Pete Becker Jan 26 '23 at 17:37
  • @Pete But, is a statement like `int a = 3;` actually using an assignment? [Relevant?](https://stackoverflow.com/q/26044416/10871073) – Adrian Mole Jan 26 '23 at 17:38
  • 1
    @AdrianMole That's a standard [copy-initialization](https://en.cppreference.com/w/cpp/language/copy_initialization), just that no copy-constructor is called (since fundamental types like `int` doesn't have constructors). – Some programmer dude Jan 26 '23 at 17:42
  • @AdrianMole `type variable_name = something;` is always copy initialization, never assignment. `variable_name = something;` is always assignment. – NathanOliver Jan 26 '23 at 17:45
  • Isn't there also assignment initialization where you can go `int a(3);` and get the same effect? Note* I know it's rather frowned on in general. I was referring to this in my head when talking in my question. – Chthonic One Jan 26 '23 at 17:47
  • @ChthonicOne `int a(3);` is called direct initialization. You can see the different types here: https://en.cppreference.com/w/cpp/language/initialization – NathanOliver Jan 26 '23 at 17:49
  • Thank you, I had seen this and lost track of it again. The fact that there are 6 different types of initialization in C++ vs. 2 in C or 3 in Java boggles my mind, and I'm having a little trouble wrapping my head around why I'd use different types and when. – Chthonic One Jan 26 '23 at 17:58
  • 1
    There's more than 6. If you want a rundown and have an hour to kill, [The Nightmare of Initialization in C++](https://www.youtube.com/watch?v=7DTlWPgX6zs&t=3s) by Nicolai Josuttis. – Eljay Jan 26 '23 at 18:26
  • "Note* I know it's rather frowned on in general" what do you mean? Why is it "frowned upon" ? Direct initialization is used all over the place. I'd have to spend a year of fixing code if suddely it would be frowned up ;) – 463035818_is_not_an_ai Jan 26 '23 at 18:48
  • I've been told it's frowned upon because `int a(3);` is direct initialization while `int a();` is function declaration. As such it can be confusing to look at. – Chthonic One Jan 26 '23 at 19:53
  • @ChthonicOne - That has been fixed by allowing `int a{3};` and `int a{};`. "Look ma, no functions!" – BoP Jan 26 '23 at 21:26

3 Answers3

3

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).

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
apple apple
  • 10,292
  • 2
  • 16
  • 36
2

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.
Martin York
  • 257,169
  • 86
  • 333
  • 562
1

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

user18533375
  • 175
  • 1
  • 2
    Clarification, pre-C++17, compilers were allowed to elide the copy. Since C++17, compilers are required to elide the copy. – Eljay Jan 26 '23 at 18:28