WEBVTT

00:00.120 --> 00:07.770
Hello again! In this video, we are going to look emplacement. Emplacement came in, in C++11.

00:08.250 --> 00:11.940
It provides us with another way to insert elements into containers.

00:12.690 --> 00:19.140
So, why is this needed? With the existing interface - functions like insert() and push_back()

00:19.860 --> 00:26.010
- these assume that you already have an object of the correct type for the container, and it will copy

00:26.010 --> 00:27.930
this object into the new element.

00:28.290 --> 00:33.390
And that is fine if you already have an object of the right type and you are going to use it again later.

00:34.090 --> 00:34.810
Quite often, though,

00:34.830 --> 00:39.690
when you are populating a container object, you just have some data and you do not have the right kind

00:39.690 --> 00:40.200
of object.

00:41.010 --> 00:46.020
So this means that you have to create an object of the right type, then insert it, and then you have an

00:46.020 --> 00:47.970
object which you are not going to use again.

00:51.690 --> 00:57.810
With emplacement, the container will actually create the new object directly in the new element.

00:58.260 --> 01:02.640
So this avoids a call to the copy constructor. And if you have a large container, that may make a

01:02.640 --> 01:03.690
noticeable difference.

01:06.260 --> 01:07.940
So to clarify this a bit,

01:08.420 --> 01:16.340
let's say we have a vector of some objects, and we want to insert a new object, with these arguments

01:16.340 --> 01:17.120
to the constructor.

01:18.410 --> 01:22.880
We can create a local variable, and pass the constructor arguments when we declare it.

01:23.540 --> 01:28.850
And then when we call insert(), we give it the iterator where we are going to add the element, and this

01:28.850 --> 01:29.570
local variable.

01:31.030 --> 01:33.670
And then we have this variable, which we are probably not going to use again.

01:35.320 --> 01:39.520
Alternatively, we can pass a constructor call as the second argument to insert.

01:40.480 --> 01:45.700
So this will create a temporary object, which gets destroyed when the insert() call returns.

01:46.420 --> 01:53.710
So this is slightly better, but we still have this copy operation, which we want to avoid. With

01:53.710 --> 01:54.190
emplace(),

01:54.200 --> 01:58.770
We pass the arguments to the constructor as part of the emplace() call.

01:59.260 --> 02:00.580
So we have the iterator,

02:01.760 --> 02:03.950
and then the constructor arguments.

02:04.670 --> 02:11.030
So the vector will create a new element, then it will call the constructor for "refrigerator", with

02:11.030 --> 02:17.330
these as the arguments to the constructor. And that will create a new object in the new element, avoiding

02:17.330 --> 02:17.960
any copying.

02:20.380 --> 02:24.190
So here is some code for that. We have our refrigerator class, which we've used before.

02:24.820 --> 02:28.540
We have a vector of these refrigerators, which is initially empty.

02:30.370 --> 02:31.930
We are going to add some elements.

02:32.710 --> 02:35.560
First, we create a local variable and call insert().

02:36.670 --> 02:38.920
Then we call insert() with a constructor call.

02:39.490 --> 02:45.130
So these are both going to create an object and then copy it into the new element. And then we are

02:45.130 --> 02:46.240
going to call emplace().

02:46.810 --> 02:53.180
So this will create a new element and then create a new object, which will use these as arguments to

02:53.180 --> 02:53.830
the constructor.

02:57.080 --> 02:59.150
And then we have a vector of three elements.

02:59.810 --> 03:01.940
So these were created using a copy.

03:02.270 --> 03:04.790
And this one was created without making a copy.

03:08.560 --> 03:14.140
So we can use emplace instead of insert. There is also an emplace_back() which we can use instead of

03:14.140 --> 03:14.440
push_back().

03:15.010 --> 03:20.590
And that does something similar. So we can pass the constructor arguments to emplace_back().

03:21.340 --> 03:27.820
This will create a new element at the back of the container, and it will create an object, in that new

03:27.820 --> 03:30.670
element, with these arguments to the constructor.

03:33.410 --> 03:39.020
There's also emplace_front() which you can use instead of push_front(). For the container adaptors with

03:39.020 --> 03:40.790
push(), you can use emplace().

03:44.780 --> 03:51.590
So here is the same code again, but we are using push_back() and emplace_back() instead of insert() and

03:51.590 --> 03:52.130
emplace().

03:53.940 --> 03:55.020
And we get the same results.

03:58.570 --> 04:02.860
Unfortunately, there is a slight oddity in the way that emplacement is specified

04:02.890 --> 04:10.600
if the container has unique keys. So this means map and set. In this case emplace() will always create

04:10.600 --> 04:11.290
a temporary object.

04:12.070 --> 04:16.000
Then it will check if there is already an element in the container which has that key.

04:16.900 --> 04:20.080
And if there is not, then it will insert that object.

04:20.530 --> 04:21.970
So that is not really very efficient.

04:22.780 --> 04:29.740
C++17 fixes this by providing a new function called try_emplace(), and this does the obvious thing.

04:30.010 --> 04:32.760
It checks for duplicates before creating any objects.

04:34.360 --> 04:38.170
And if there already is an element with the same key, then nothing will happen.

04:40.900 --> 04:47.500
So what happens if it does need to create a new element? The elements of a map are a pair, so there are

04:47.500 --> 04:51.010
actually two members that needs to be initialized, "first" and "second".

04:51.790 --> 04:56.980
And these are initialized by calling the constructors. And that is known as "piece-wise construction".

04:58.670 --> 05:04.670
The first argument to try_emplace() will be the key of the new element, and the rest of the arguments

05:04.670 --> 05:08.450
will be forwarded to the constructor of the value member.

05:10.460 --> 05:16.220
The return value from try_emplace() is the same as for insert(). So we get an iterator and a bool.

05:20.090 --> 05:23.900
So now we are using a map and some C++ 17 features.

05:26.700 --> 05:31.230
The key to the map is a string, and the value is a refrigerator.

05:32.130 --> 05:33.280
So we do something similar.

05:33.300 --> 05:40.740
We insert a local variable, insert_or_assign(). And then we call insert_or_assign() with a constructor call.

05:41.280 --> 05:48.900
So these are both going to perform a copy, into the new element. And then we call try_emplace(), and

05:48.900 --> 05:53.040
this will create the key, in place, and the value, in place.

05:57.330 --> 05:58.170
So there we are.

06:04.410 --> 06:10.200
So how useful is this? If you have a container of objects which cannot be copied or (we will cover this later!)

06:10.200 --> 06:14.280
moved, then emplacement is the only way that you can populate your container.

06:14.580 --> 06:20.370
The only way to insert elements. There are some circumstances in which emplacement will cause a temporary

06:20.370 --> 06:21.900
object to be created.

06:22.740 --> 06:26.460
If the container does not allow duplicates, which we have just discussed.

06:28.020 --> 06:35.070
If the implementation uses assignments rather than copying for populating its elements. Or if a type

06:35.070 --> 06:40.170
conversion is required. If you have a type conversion, then there must be an object to convert!

06:42.290 --> 06:46.580
Modern compilers are actually very good at optimizing away copies of temporary objects.

06:47.180 --> 06:52.490
And we also have move semantics in C++11, which often means you can avoid copying temporary objects

06:52.490 --> 06:53.010
altogether.

06:53.870 --> 07:00.350
So this would probably have been very useful in C++98, but in C++11, it is, probably, a bit doubtful.

07:03.230 --> 07:04.970
Although it does have one good use case.

07:05.750 --> 07:07.350
Okay, so that is it for this video.

07:07.640 --> 07:10.640
I will see you next time, but until then, keep coding!
