zoukankan      html  css  js  c++  java
  • 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的区别

  • 相关阅读:
    CodeForces 19D Points (线段树+set)
    FZU 2105 Digits Count
    HDU 5618 Jam's problem again(三维偏序,CDQ分治,树状数组,线段树)
    HDU 5634 Rikka with Phi (线段树)
    Java实现 蓝桥杯 算法提高 转圈游戏(暴力快速幂)
    Java实现 蓝桥杯 算法提高 转圈游戏(暴力快速幂)
    Java实现 蓝桥杯 算法提高 转圈游戏(暴力快速幂)
    Java实现 蓝桥杯 算法提高VIP Substrings(暴力)
    Java实现 蓝桥杯 算法提高VIP Substrings(暴力)
    Java实现 蓝桥杯 算法提高VIP Substrings(暴力)
  • 原文地址:https://www.cnblogs.com/dream397/p/15094316.html
Copyright © 2011-2022 走看看