emplace_back和push_back区别以及移动构造函数

本文通过具体的测试代码,详细对比了C++中容器成员函数emplace_back与push_back在不同参数类型下的行为差异,包括左值、右值及参数列表等场景,并分析了构造、移动构造、拷贝构造及析构的过程。
部署运行你感兴趣的模型镜像

先说结论:
结论 :
1、emplace_back以参数列表的形式传入时,不论是否有移动构造函数,都是原地构造,只会调用一次构造函数
2、emplace_back以左值对象的形式传入时,不论是否有移动构造函数,都是调用一次拷贝构造函数

3、emplace_back以右值对象(例如move(左值对象),或者就是右值)的形式传入时
a、有移动构造函数,调用一次移动构造
b、没有移动构造函数,调用拷贝构造函数
4、emplace_back以Person(“aaa”, “shandong”, 1991)形式传入时
a、有移动构造函数,构造临时文件 移动构造 临时文件析构
b、没有移动构造函数,构造临时文件 拷贝构造 临时文件析构

1、push_back以参数列表的形式传入时
a、有移动构造函数,构造临时文件 移动构造 临时文件析构
b、没有移动构造函数,构造临时文件 拷贝构造 临时文件析构
2、push_back以左值对象的形式传入时,不论是否有移动构造函数,都是调用一次拷贝构造函数

3、push_back以右值对象(例如move(左值对象),或者就是右值)的形式传入时
a、有移动构造函数,调用一次移动构造
b、没有移动构造函数,调用拷贝构造函数
4、push_back以Person(“aaa”, “shandong”, 1991)形式传入时
a、有移动构造函数,构造临时文件 移动构造 临时文件析构
b、没有移动构造函数,构造临时文件 拷贝构造 临时文件析构

测试代码:

#include <vector>  
#include <string>  
#include <iostream>  
using namespace std;
 
struct Person  
{  
    string name;  
    string country;  
    int year;  
 
    Person(string p_name,  string p_country, int p_year)  
        : name(p_name), country(p_country), year(p_year)  
    {  
         cout << "I am being constructed1.\n";  
    }
    
    Person(const char * p_name)  
        : name(p_name), country("defaule"), year(1)  
    {  
         cout << "I am being constructed2.\n";  
    }
    
    Person(const Person& other)
        : name(other.name), country(other.country), year(other.year)
    {
         cout << "I am being copy constructed.\n";
    }

    Person(Person&& other)  
        : name(other.name), country(other.country), year(other.year)  
    {  
         cout << "I am being moved  constructed.\n";  
    }

    ~Person()
    {
        cout << "I am being destructed.\n";
    }
    Person& operator=(const Person& other);  
};  
 
int main()  
{  
    Person p1("aaa", "shandong", 1991);
    Person p2("aaa", "shandong", 1991);
    Person p3("aaa", "shandong", 1991);
    Person p4("aaa", "shandong", 1991);
    
    vector<Person> vec0;  
    cout << "\nemplace_back0:\n";  
    vec0.emplace_back(p1); //复制构造  p1为左值   若将移动构造函数注释 复制构造
    
    vector<Person> vec1;  
    cout << "\nemplace_back1:\n";  
    vec1.emplace_back(move(p2)); //移动构造  move之后p2当做右值  若将移动构造函数注释 复制构造
    
    vector<Person> vec2;  
    cout << "\nemplace_back2:\n";  
    vec2.emplace_back("aaa", "shandong", 1991); //只有原地构造  若将移动构造函数注释 原地构造
    
    vector<Person> vec3;  
    cout << "\nemplace_back3:\n";  
    vec3.emplace_back("aaa"); //只有原地构造  若将移动构造函数注释 原地构造
    
    vector<Person> vec4;  
    cout << "\nemplace_back4:\n";  
    vec4.emplace_back(Person("aaa", "shandong", 1991)); //构造临时文件 移动构造  临时文件析构 若将移动构造函数注释 构造临时文件 复制构造  临时文件析构
    
    vector<Person> Vec0;  
    cout << "\npush_back0:\n";  
    Vec0.push_back(p3); //复制构造  p3为左值  若将移动构造函数注释 复制构造
    
    vector<Person> Vec1; 
    cout << "\npush_back1:\n"; 
    Vec1.push_back(move(p4));//移动构造  move之后p4当做右值  若将移动构造函数注释 复制构造
    
    vector<Person> Vec2;  
    cout << "\npush_back2:\n";  
    Vec2.push_back(Person("bbb", "jaingsu", 1993)); //构造临时文件 移动构造  临时文件析构 若将移动构造函数注释 构造临时文件 复制构造  临时文件析构
    
    vector<Person> Vec3; 
    cout << "\npush_back3:\n"; 
    Vec3.push_back("ccc");//构造临时文件 移动构造  临时文件析构  若将移动构造函数注释 构造临时文件 复制构造  临时文件析构
    
    vector<Person> Vec4; 
    cout << "\npush_back4:\n"; 
    Vec4.push_back(Person("aaa", "shandong", 1991));//构造临时文件 移动构造  临时文件析构  若将移动构造函数注释 构造临时文件 复制构造  临时文件析构
    cout<<endl;
}

输出如下:

I am being constructed1.
I am being constructed1.
I am being constructed1.
I am being constructed1.

emplace_back0:
I am being copy constructed.

emplace_back1:
I am being moved constructed.

emplace_back2:
I am being constructed1.

emplace_back3:
I am being constructed2.

push_back0:
I am being copy constructed.

push_back1:
I am being moved constructed.

push_back2:
I am being constructed1.
I am being moved constructed.
I am being destructed.

push_back3:
I am being constructed2.
I am being moved constructed.
I am being destructed.

I am being destructed.
I am being destructed.
I am being destructed.
I am being destructed.
I am being destructed.
I am being destructed.
I am being destructed.
I am being destructed.
I am being destructed.
I am being destructed.
I am being destructed.
I am being destructed.

若将移动构造函数注释掉 输出如下:
I am being constructed1.
I am being constructed1.
I am being constructed1.
I am being constructed1.

emplace_back0:
I am being copy constructed.

emplace_back1:
I am being copy constructed.

emplace_back2:
I am being constructed1.

emplace_back3:
I am being constructed2.

push_back0:
I am being copy constructed.

push_back1:
I am being copy constructed.

push_back2:
I am being constructed1.
I am being copy constructed.
I am being destructed.

push_back3:
I am being constructed2.
I am being copy constructed.
I am being destructed.

I am being destructed.
I am being destructed.
I am being destructed.
I am being destructed.
I am being destructed.
I am being destructed.
I am being destructed.
I am being destructed.
I am being destructed.
I am being destructed.
I am being destructed.
I am being destructed.

您可能感兴趣的与本文相关的镜像

ACE-Step

ACE-Step

音乐合成
ACE-Step

ACE-Step是由中国团队阶跃星辰(StepFun)与ACE Studio联手打造的开源音乐生成模型。 它拥有3.5B参数量,支持快速高质量生成、强可控性和易于拓展的特点。 最厉害的是,它可以生成多种语言的歌曲,包括但不限于中文、英文、日文等19种语言

`emplace_back``push_back`是C++标准库容器(如`std::vector`、`std::list`等)用来向容器尾部添加元素的成员函数,二者存在以下区别: ### 函数类型 - `emplace_back`是函数模板,且是可变参数模板,通过传入不同参数类型,实例化出不同类型的`emplace_back`函数;`push_back`是类成员函数[^1]。 ### 底层实现 - `emplace_back`直接接受构造对象所需的参数列表,在容器内部直接构造对象,避免临时对象的创建。 ```cpp #include <vector> #include <iostream> class Vertex { public: Vertex(int x, int y, int z) { std::cout << "Vertex constructor called" << std::endl; } Vertex(const Vertex&) { std::cout << "Vertex copy constructor called" << std::endl; } Vertex(Vertex&&) { std::cout << "Vertex move constructor called" << std::endl; } }; int main() { std::vector<Vertex> vec1; vec1.push_back(Vertex(1, 2, 3)); std::vector<Vertex> vec2; vec2.emplace_back(1, 2, 3); return 0; } ``` ### 性能差异 对于`std::vector<int>`这样的基本数据类型,`push_back``emplace_back`的性能差异通常是微乎其微的,因为它们的行为在这种情况下是相似的。但对于大型或复杂对象,性能差异明显: - `push_back`若传递对象,可能涉及临时对象的构造及后续的拷贝/移动操作,尤其对大型或复杂对象性能影响显著。 - `emplace_back`直接在容器内存中构造对象,省去临时对象的步骤,性能更优。例如,对于包含多个参数的构造函数,`emplace_back`减少了一次构造一次移动/拷贝操作[^2][^3][^4]。 ### 适用场景 - 优先使用`emplace_back`的情况:需要直接通过构造参数添加元素时,尤其是对象构造开销较大时。 - 使用`push_back`的情况:已有现成对象需插入容器,或代码可读性更重要时(如明确传递对象)[^3][^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值