我想看看push_back和emplace_back之间的区别,因为在一些地方,我读了建议,因为现在最好使用emplace_back,因为“它可以完成所有push_back可以做的事情甚至更多”,所以我希望ti的效率更高。但令我惊讶的是

#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;
}

输出为
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 const时复制一个。我检查了g++(Ubuntu 7.4.0-1ubuntu1〜16.04〜ppa1)7.4.0和online C++ shell
我想念什么吗?

最佳答案

push_back效率不高,您观察到的结果归因于 vector 本身的大小调整。

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

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

#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;
}

相应的输出是:
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!换句话说,我们改变
va.emplace_back(A());


va.emplace_back(); // No arguments necessary since A is default-constructed

结果是没有拷贝,也没有移动:
push:
A const
A move const
A dest

emplace:
A const

end:
A dest
A dest

关于 vector 大小调整的注释:需要注意的是,std::vector的实现很聪明。如果A是普通的可复制类型,则std::vector可以使用类似于realloc的系统功能就地调整大小而无需额外复制。但是,由于A的构造函数和销毁包含代码,因此无法在此处使用realloc

关于c++ - push_back比emplace_back更有效?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/62011157/

10-11 23:12
查看更多