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的区别

  • 相关阅读:
    web服务器iis安全设置
    Log explorer for sql server
    C#将image中的显示的图片转换成二进制
    .Net平台开发的技术规范与实践精华总结
    .net面试题整理
    Javascript 刷新框架及页面的方法总集
    WEB程序代码优化入手的几方面
    用js控制网页播放器
    SQL Server2000中死锁经验总结
    专家谈CSS设计
  • 原文地址:https://www.cnblogs.com/dream397/p/15094316.html
Copyright © 2011-2022 走看看