push_back and emplace_back

Hi all,

I know, say, for an std::vector, push_back(x) means to copy or move x to the end of the vector and emplace_back(x) means to construct x at the end of the vector but can't understand that difference well!
Could you explain that a little more (and if there's also some code used for both to demonstrate their difference, it will be more appreciated)?
Last edited on
For a non-trivial type, emplace_back() (construct in-place) is obviously faster than creating an object first and then copy constructing it into the vector. (when reallocation does dot take place). Depending on how efficient the move is, and how clever the optimiser is, emplace_back() may not be significantly faster than constructing a temporary object and then move constructing it into the vector.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <iostream>
#include <ctime>
#include <vector>

int main()
{
    const std::size_t STR_SZ = 100 ;
    const std::size_t N = 4'000'000 ;

    {
        std::vector<std::string> vec ;
        vec.reserve(N) ;

        const auto start = std::clock() ;
        while( vec.size() < N )
        {
            std::string str( STR_SZ, ' ' ) ; // construct a string
            vec.push_back(str) ; // copy construct it into the vector
        }
        const auto end = std::clock() ;
        std::cout << "push_back (copy): " << (end-start) * 1000.0 / CLOCKS_PER_SEC << " millisecs\n" ;
    }

    {
        std::vector<std::string> vec ;
        vec.reserve(N) ;

        const auto start = std::clock() ;
        while( vec.size() < N )
        {
            vec.push_back( std::string( STR_SZ, ' ' ) ) ; // construct a emporary string and move it into the vector
        }
        const auto end = std::clock() ;
        std::cout << "push_back (move): " << (end-start) * 1000.0 / CLOCKS_PER_SEC << " millisecs\n" ;
    }

    {
        std::vector<std::string> vec ;
        vec.reserve(N) ;

        const auto start = std::clock() ;
        while( vec.size() < N )
        {
            vec.emplace_back( STR_SZ, ' ' ) ; // construct a string in-place in the vector
        }
        const auto end = std::clock() ;
        std::cout << "emplace_back: " << (end-start) * 1000.0 / CLOCKS_PER_SEC << " millisecs\n" ;
    }
}

http://coliru.stacked-crooked.com/a/152379fed93c0885
For a non-trivial type, emplace_back() (construct in-place) is obviously faster than creating an object first and then copy constructing it into the vector. (when reallocation does dot take place). Depending on how efficient the move is, and how clever the optimiser is, emplace_back() may not be significantly faster than constructing a temporary object and then move constructing it into the vector.
What do you mean by a non-trivial type?
And, what does constructing in place mean, please?
Last edited on
> What do you mean by a non-trivial type?

By non-trivial, I meant a type which has some measurable overhead for construction and copy.

I should have used different terminology to avoid confusion; the standard is stricter:
A trivial class is a class that is trivially copyable and has one or more eligible default constructors, all of which are trivial.
https://eel.is/c++draft/class.prop#2



> And, what does constructing in place mean, please?

It means construct the object directly in the storage allocated by the vector instead of creating an object outside the vector and then copying/moving it into the storage allocated by the vector.

Here is an illustration:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <iostream>
#include <vector>

int main()
{
    struct A
    {
        A( int i, double d ) : i(i), d(d) { std::cout << "constructed object at address " << this << '\n' ; }
        A( const A& that ) : i(that.i), d(that.d)
        {
            std::cout << "copy constructed object at address " << this
                      << " (from object at address " << std::addressof(that) << ")\n" ;
        }
        // ...

        int i ;
        double d ;
    };

    std::vector<A> vec ;
    vec.reserve(10) ;

    // construct a temporary A and copy it into the vector
    vec.push_back( A(1,2.3) ) ;
    // constructed object at address aaaaaaaa
    // copy constructed object at address bbbbbbbb (from object at address aaaaaaaa)
    std::cout << "object added is in the vector at address " << std::addressof( vec.back() ) << '\n' ;
    // object added is in the vector at address 0x16ce8301ac0

    std::cout << '\n' ;

    // construct A in-place in the vector
    vec.emplace_back(4,5.6) ;
    // constructed object at address cccccccc
    std::cout << "object added is in the vector at address " << std::addressof( vec.back() ) << '\n' ;
    // object added is in the vector at address cccccccc
}

http://coliru.stacked-crooked.com/a/912712f737a83c46
So for built-in types, there's no difference between the two, yeah? For instance,

1
2
3
4
std::vector<int> vi;
for(int i=0; i<10; ++i)
 vi.push_back(i);
 // or vi.emplace_back(i); 


And regarding your code, probably vec.emplace_back(A(4,5.6)); would do the same as vec.push_back(A(4,5.6));, not?
> So for built-in types, there's no difference between the two, yeah?

Right.


> vec.emplace_back(A(4,5.6)); would do the same as vec.push_back(A(4,5.6));

Yes.
Topic archived. No new replies allowed.