首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >push_back比emplace_back更有效?

push_back比emplace_back更有效?
EN

Stack Overflow用户
提问于 2020-05-25 21:36:14
回答 1查看 444关注 0票数 5

我希望看到push_back和emplace_back之间的区别,因为在我看过推荐的几个地方,现在最好使用emplace_back作为“它可以做所有push_back可以做的事情,也可以做更多”,所以我希望ti会更有效率。但令我惊讶的是

代码语言:javascript
复制
#include <iostream>     
#include <vector>    

class A
{
    public:
    A() {std::cout << "A const" << std::endl;}
    ~A() {std::cout << "A dest" << std::endl;}
    A(const A& a) {std::cout << "A copy const" << std::endl;}
    A(A&& a) {std::cout << "A move const" << std::endl;}
    A& operator=(const A& a) {std::cout << "A copy operator=" << std::endl; return *this; }
    A& operator=(A&& a) {std::cout << "A move operator=" << std::endl;  return *this; }
};

int main () {
    std::vector<A> va;
    std::cout <<"push:" << std::endl;
    va.push_back(A());
    std::cout <<std::endl<< "emplace:" << std::endl;
    va.emplace_back(A());

    std::cout <<std::endl<< "end:" << std::endl;

    return 0;
}

输出是

代码语言:javascript
复制
push:
A const
A move const
A dest

emplace:
A const
A move const
A copy const
A dest
A dest

end:
A dest
A dest

emplace_back调用move构造函数,然后在push_back只调用一个move时复制构造函数。我检查了g++ (Ubuntu7.4.0-1ubuntu1~16.04~ppa1 1) 7.4.0和在线C++外壳。我是不是遗漏了什么?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-05-25 21:41:28

push_back 效率不高,您所观察到的结果是向量自身调整大小的结果。

当您在emplace之后调用push_back时,向量必须自行调整大小,以便为第二个元素腾出空间。这意味着它必须移动最初位于向量内的A,从而使emplace看起来更加复杂。

如果事先在向量中预留了足够的空间,这种情况就不会发生。请注意在创建va.reserve(2)之后对va的调用:

代码语言:javascript
复制
#include <iostream>     
#include <vector>    

class A
{
    public:
    A() {std::cout << "A const" << std::endl;}
    ~A() {std::cout << "A dest" << std::endl;}
    A(const A& a) {std::cout << "A copy const" << std::endl;}
    A(A&& a) {std::cout << "A move const" << std::endl;}
    A& operator=(const A& a) {std::cout << "A copy operator=" << std::endl; return *this; }
    A& operator=(A&& a) {std::cout << "A move operator=" << std::endl;  return *this; }
};

int main () {
    std::vector<A> va;
    // Now there's enough room for two elements
    va.reserve(2);
    std::cout <<"push:" << std::endl;
    va.push_back(A());
    std::cout <<std::endl<< "emplace:" << std::endl;
    va.emplace_back(A());

    std::cout <<std::endl<< "end:" << std::endl;

    return 0;
}

相应的输出是:

代码语言:javascript
复制
push:
A const
A move const
A dest

emplace:
A const
A move const
A dest

end:
A dest
A dest

我们能让事情变得更有效率吗?是的!emplace_back接受您提供的任何参数,并将它们转发给A的构造函数。因为A有一个不带参数的构造函数,所以也可以使用不带参数的emplace_back!换句话说,我们改变了。

代码语言:javascript
复制
va.emplace_back(A());

代码语言:javascript
复制
va.emplace_back(); // No arguments necessary since A is default-constructed

这将导致不复制,也不会移动:

代码语言:javascript
复制
push:
A const
A move const
A dest

emplace:
A const

end:
A dest
A dest

关于向量调整大小的注意事项:需要注意的是,std::vector的实现是明智的。如果A是一种微不足道的可复制类型,那么std::vector就可以在不使用类似于realloc的系统功能的情况下调整相应的大小。但是,由于A的构造函数和破坏包含代码,所以不能在这里使用realloc

票数 12
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62011157

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档