C++中push_back和emplace_back的区别

将 emplace_back() 和 push_back() 中区别最大的程序拎出来看:

_Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish,
                                 std::forward<_Args>(__args)...); // emplace_back()
_Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish,
                                 __x);                            // push_back()

对于 std::forward() 函数而言,本质上是一个类型转换函数,它的声明函数如下所示:

/**
 *  以下程序来自STL源码 bits/move.h
 *  @brief  Forward an lvalue.
 *  @return The parameter cast to the specified type.
 *
 *  This function is used to implement "perfect forwarding".
 */
template<typename _Tp>
constexpr _Tp &&forward(typename std::remove_reference<_Tp>::type &__t) noexcept {
    return static_cast<_Tp &&>(__t);
}
/**
 * Created by Xiaozhong on 2020/9/3.
 * Copyright (c) 2020/9/3 Xiaozhong. All rights reserved.
 */

#include <vector>
#include <iostream>

using namespace std;

class Person {
    int _age;

public:
    Person(int age) : _age(age) {
        cout << "Construct a person." << _age << endl;
    }

    Person(const Person &p) : _age(p._age) {
        cout << "Copy-Construct" << _age << endl;
    }

    Person(const Person &&p) noexcept: _age(p._age) {
        cout << "Move-Construct" << _age << endl;
    }
};

#define TEST_EMPLACE_BACK
//#define TEST_PUSH_BACK

int main() {
    vector<Person> person;
    auto p = Person(1); // >: Construct a person.1
#ifdef TEST_EMPLACE_BACK
    person.emplace_back(move(p)); // >: Move-Construct1
    person.emplace_back(2);
    /**
     * >: Construct a person.2  // 构建一个新的元素
     * >: Move-Construct1       // 拷贝之前的元素过来,这个时候用的是 Person(const Person &&p)
     */
#endif
#ifdef TEST_PUSH_BACK
    person.push_back(p);
    /**
     * >: Copy-Construct1 因为容器扩容,需要把前面的元素重新添加进来,因此需要拷贝
     */
#endif
}
root@ubuntu:~/c++# g++ -std=c++11 push.cpp -o push
root@ubuntu:~/c++# ./push
Construct a person.1
Move-Construct1
Construct a person.2
Move-Construct1
root@ubuntu:~/c++# 
#include <vector>
#include <iostream>

using namespace std;

class Person {
    int _age;

public:
    Person(int age) : _age(age) {
        cout << "Construct a person." << _age << endl;
    }

    Person(const Person &p) : _age(p._age) {
        cout << "Copy-Construct" << _age << endl;
    }

    Person(const Person &&p) noexcept: _age(p._age) {
        cout << "Move-Construct" << _age << endl;
    }
};

#define TEST_EMPLACE_BACK
//#define TEST_PUSH_BACK

int main() {
    vector<Person> person;
    auto p = Person(1); // >: Construct a person.1
#ifdef TEST_EMPLACE_BACK
    cout << "back " << endl;
    person.emplace_back(p); 
    cout << "back move" << endl;
    person.emplace_back(move(p)); // >: Move-Construct1
    cout << "back 2" << endl;
    person.emplace_back(2);
    /**
     * >: Construct a person.2  // 构建一个新的元素
     * >: Move-Construct1       // 拷贝之前的元素过来,这个时候用的是 Person(const Person &&p)
     */
#endif
#ifdef TEST_PUSH_BACK
    person.push_back(p);
    /**
     * >: Copy-Construct1 因为容器扩容,需要把前面的元素重新添加进来,因此需要拷贝
     */
#endif
}
root@ubuntu:~/c++# g++ -std=c++11 push.cpp -o push
root@ubuntu:~/c++# ./push
Construct a person.1
back 
Copy-Construct1
back move
Move-Construct1
Move-Construct1
back 2
Construct a person.2
Move-Construct1
Move-Construct1
#include <vector>
#include <iostream>

using namespace std;

class Person {
    int _age;

public:
    Person(int age) : _age(age) {
        cout << "Construct a person." << _age << endl;
    }

    Person(const Person &p) : _age(p._age) {
        cout << "Copy-Construct" << _age << endl;
    }

    Person(const Person &&p) noexcept: _age(p._age) {
        cout << "Move-Construct" << _age << endl;
    }
};

//#define TEST_EMPLACE_BACK
#define TEST_PUSH_BACK

int main() {
    vector<Person> person;
    auto p = Person(1); // >: Construct a person.1
#ifdef TEST_EMPLACE_BACK
    person.emplace_back(move(p)); // >: Move-Construct1
    person.emplace_back(2);
    /**
     * >: Construct a person.2  // 构建一个新的元素
     * >: Move-Construct1       // 拷贝之前的元素过来,这个时候用的是 Person(const Person &&p)
     */
#endif
#ifdef TEST_PUSH_BACK
    person.push_back(p);
    /**
     * >: Copy-Construct1 因为容器扩容,需要把前面的元素重新添加进来,因此需要拷贝
     */
#endif
}
root@ubuntu:~/c++# g++ -std=c++11 push.cpp -o push
root@ubuntu:~/c++# ./push
Construct a person.1
Copy-Construct1
root@ubuntu:~/c++# 

emplace_back() 函数在原理上比 push_back() 有了一定的改进,包括在内存优化方面和运行效率方面。内存优化主要体现在使用了就地构造(直接在容器内构造对象,不用拷贝一个复制品再使用)+强制类型转换的方法来实现,在运行效率方面,由于省去了拷贝构造过程,因此也有一定的提升。

#include <vector>
#include <iostream>

using namespace std;

class Person {
    int _age;

public:
    Person(int age) : _age(age) {
        cout << "Construct a person." << _age << endl;
    }

    Person(const Person &p) : _age(p._age) {
        cout << "Copy-Construct" << _age << endl;
    }

    Person(const Person &&p) noexcept: _age(p._age) {
        cout << "Move-Construct" << _age << endl;
    }
};

//#define TEST_EMPLACE_BACK
#define TEST_PUSH_BACK

int main() {
    vector<Person> person;
    auto p = Person(1); // >: Construct a person.1
#ifdef TEST_EMPLACE_BACK
    cout << "back " << endl;
    person.emplace_back(p); 
    cout << "back move" << endl;
    person.emplace_back(move(p)); // >: Move-Construct1
    cout << "back 2" << endl;
    person.emplace_back(2);
    /**
     * >: Construct a person.2  // 构建一个新的元素
     * >: Move-Construct1       // 拷贝之前的元素过来,这个时候用的是 Person(const Person &&p)
     */
#endif
#ifdef TEST_PUSH_BACK
    person.push_back(p);
    cout << "second push back " << endl;
    person.push_back(p);
    cout << "third push back " << endl;
    person.push_back(p);
    /**
     * >: Copy-Construct1 因为容器扩容,需要把前面的元素重新添加进来,因此需要拷贝
     */
#endif
}
root@ubuntu:~/c++# ./push
Construct a person.1
Copy-Construct1
second push back 
Copy-Construct1 -------------
Move
-Construct1 third push back Copy-Construct1 -------插入的时候总是copy Move-Construct1 Move-Construct1

C++中push_back和emplace_back的区别

原文地址:https://www.cnblogs.com/dream397/p/15094316.html