- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我目前正在自学 C++,我很好奇 push_back()
和 emplace_back()
是如何工作的。当您尝试构建大型对象并将其推到容器的背面时,我一直认为 emplace_back()
更快。
假设我有一个 Student
对象,我想将其附加到 Students vector 的后面。
struct Student {
string name;
int student_ID;
double GPA;
string favorite_food;
string favorite_prof;
int hours_slept;
int birthyear;
Student(string name_in, int ID_in, double GPA_in, string food_in,
string prof_in, int sleep_in, int birthyear_in) :
/* initialize member variables */ { }
};
假设我调用 push_back()
并将一个 Student
对象推到 vector 的末尾:
vector<Student> vec;
vec.push_back(Student("Bob", 123456, 3.89, "pizza", "Smith", 7, 1997));
我这里的理解是,push_back
在 vector 之外创建了一个 Student
对象的实例,然后将它移到 vector 的后面。
我也可以放置而不是推送:
vector<Student> vec;
vec.emplace_back("Bob", 123456, 3.89, "pizza", "Smith", 7, 1997);
我的理解是 Student 对象是在 vector 的最后面构造的,因此不需要 move 。
因此,放置会更快是有道理的,尤其是在添加许多 Student 对象的情况下。但是,当我对这两个版本的代码进行计时时:
for (int i = 0; i < 10000000; ++i) {
vec.push_back(Student("Bob", 123456, 3.89, "pizza", "Smith", 7, 1997));
}
和
for (int i = 0; i < 10000000; ++i) {
vec.emplace_back("Bob", 123456, 3.89, "pizza", "Smith", 7, 1997);
}
我预计后者会更快,因为不必 move 大型 Student 对象。奇怪的是,emplace_back
版本最终变慢了(经过多次尝试)。我还尝试插入 10000000 个 Student 对象,其中构造函数接收引用,push_back()
和 emplace_back()
中的参数存储在变量中。这也不起作用,因为 emplace 仍然较慢。
我已检查以确保在两种情况下插入的对象数量相同。时间差不是很大,但最终部署速度慢了几秒钟。
我对 push_back()
和 emplace_back()
工作原理的理解有问题吗?非常感谢您的宝贵时间!
根据要求,这是代码。我正在使用 g++ 编译器。
推回:
struct Student {
string name;
int student_ID;
double GPA;
string favorite_food;
string favorite_prof;
int hours_slept;
int birthyear;
Student(string name_in, int ID_in, double GPA_in, string food_in,
string prof_in, int sleep_in, int birthyear_in) :
name(name_in), student_ID(ID_in), GPA(GPA_in),
favorite_food(food_in), favorite_prof(prof_in),
hours_slept(sleep_in), birthyear(birthyear_in) {}
};
int main() {
vector<Student> vec;
vec.reserve(10000000);
for (int i = 0; i < 10000000; ++i)
vec.push_back(Student("Bob", 123456, 3.89, "pizza", "Smith", 7, 1997));
return 0;
}
安置回来:
struct Student {
string name;
int student_ID;
double GPA;
string favorite_food;
string favorite_prof;
int hours_slept;
int birthyear;
Student(string name_in, int ID_in, double GPA_in, string food_in,
string prof_in, int sleep_in, int birthyear_in) :
name(name_in), student_ID(ID_in), GPA(GPA_in),
favorite_food(food_in), favorite_prof(prof_in),
hours_slept(sleep_in), birthyear(birthyear_in) {}
};
int main() {
vector<Student> vec;
vec.reserve(10000000);
for (int i = 0; i < 10000000; ++i)
vec.emplace_back("Bob", 123456, 3.89, "pizza", "Smith", 7, 1997);
return 0;
}
最佳答案
此行为是由于 std::string
的复杂性所致。这里有一些相互作用的东西:
push_back
版本中,编译器能够在编译时确定字符串的长度,而对于 emplace_back
版本,编译器无法这样做.因此,emplace_back
调用需要调用 strlen
。此外,由于编译器不知道字符串文字的长度,它必须为 SSO 和非 SSO 情况发出代码(参见 Jason Turner 的 "Initializer Lists Are Broken, Let's Fix Them" ;这是一个长篇大论,但他遵循了插入的问题字符串到一个 vector 中)考虑这个更简单的类型:
struct type {
std::string a;
std::string b;
std::string c;
type(std::string a, std::string b, std::string c)
: a{a}
, b{b}
, c{c}
{}
};
请注意构造函数如何复制 a
、b
和c
。
Testing this against a baseline of just allocating memory ,我们可以看到 push_back
优于 emplace_back
:
Click on image for quick-bench link
因为您的示例中的字符串都适合 SSO 缓冲区,所以在这种情况下复制与 move 一样便宜。因此,构造函数非常高效,emplace_back
的改进效果较小。
此外,如果我们搜索 the assembly对于 push_back
和 emplace_back
的调用:
// push_back call
void foo(std::vector<type>& vec) {
vec.push_back({"Bob", "pizza", "Smith"});
}
// emplace_back call
void foo(std::vector<type>& vec) {
vec.emplace_back("Bob", "pizza", "Smith");
}
(这里没有复制程序集。它很大。std::string
很复杂)
我们可以看到 emplace_back
调用了 strlen
,而 push_back
没有。由于字符串文字与正在构造的 std::string
之间的距离增加,编译器无法优化对 strlen
的调用。
显式调用 std::string
构造函数会移除对 strlen
的调用,但不会再在适当的位置构造它们,因此这无法加快速度emplace_back
。
所有这一切,if we leave the SSO by using long enough strings ,分配成本完全淹没了这些细节,因此 emplace_back
和 push_back
具有相同的性能:
Click on image for quick-bench link
如果您修复 type
的构造函数以 move 其参数,emplace_back
在所有情况下都会变得更快。
struct type {
std::string a;
std::string b;
std::string c;
type(std::string a, std::string b, std::string c)
: a{std::move(a)}
, b{std::move(b)}
, c{std::move(c)}
{}
};
Click on image for quick-bench link
Click on image for quick-bench link
但是,SSO push_back
的情况变慢了;编译器似乎发出了额外的拷贝。
optimal version of perfect forwarding没有这个缺点(注意纵轴上的比例变化):
struct type {
std::string a;
std::string b;
std::string c;
template <typename A, typename B, typename C>
type(A&& a, B&& b, C&& c)
: a{std::forward<A>(a)}
, b{std::forward<B>(b)}
, c{std::forward<C>(c)}
{}
};
关于c++ - push_back() 和 emplace_back() 在幕后,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50705571/
对于要执行的JS代码,由解析器逐行解析,如果代码无效,则显示错误信息。如果一切正确,那么解析器会生成一个称为抽象语法树的数据结构。然后使用此抽象语法树为解释器生成字节码以供执行。 以上快速分析可以总结
似乎如果我在 () 中包装一个字符串、 bool 值或数字原始值,我会得到一个包装原始值的字符串、 bool 值、数字对象。这个结论正确吗? 此外,似乎 () 对于字符串和 bool 值是可选的,但对
我有几个关于 Java 中的嵌套类的问题。 关于内存分配,嵌套类是如何“隐藏”的? 您不能在嵌套类中声明静态变量(我认为确切的错误是静态属性只能在顶级类中声明)。为什么会这样?嵌套类还有哪些其他限制?
对于没有使用 Lambda Expresstions 经验的人,下面的代码让它看起来很神奇: int totalScore = File.ReadLines(@"c:/names.txt")
一个朴素的类型系统会将对象存储为指向其类型的指针(其中包含许多有用的信息,如 vtable、对象大小等),然后是其数据。如果.Net 有这样的类型系统,object在 32 位系统上占用 4 个字节,
我有以下用于字符串加密和解密的JAVA代码: public class AES { private SecretKeySpec setKey(String myKey) {
我试图了解 React 中的“组件”。 我有几个问题,所以我认为社区是提出问题的最佳场所。 1 - 当我们这样做时: var foo = React.createClass ({ ... }); Co
我想知道 ref 和 out 关键字在幕后是如何工作的?例如,如果我们在方法上使用它,它会把这个值类型变量放入某个类中以便像使用引用类型一样使用它吗? 最佳答案 in order to work wi
我对 Rails ActiveRecord、Doctrine for PHP(以及类似的 ORM)背后的一些设计很感兴趣。 ORM 如何设法实现链式访问器等功能,它们通常需要多深的工作? ORM 如何
这个问题在这里已经有了答案: 关闭 10 年前。 Possible Duplicate: C# “as” cast vs classic cast 我想知道当我做类似的事情时,.Net CLR 的底
好吧,这似乎是一个菜鸟问题,但我认识的许多 Web 开发人员都没有完全理解这个问题。 基本上,如何使用 FileUpload 控件的上传事件将文件从网页文件输入框上传到网络服务器(例如托管 .net
我很熟悉,按下返回键会导致 activity 被“销毁”,或者当开发人员调用函数 finish() 时,或者当系统需要时内存等... 并且还熟悉我们需要在 onDestroy 中执行清理过程,例如 u
我正在使用 GameViewController 和 GameScene。这个链接到 GameScene.sks。在 GameViewController 中,我将 aspect radio 设置为
关于 EF 的另一个问题: 我想知道在遍历查询结果时幕后发生了什么。 例如,查看以下代码: var activeSources = from e in entitiesContext.Sources
你好,我有一个关于 d3 的性质的问题,我认为这是关于 d3 的非常深入的细节。 据我了解, d3 中的变量声明,如 var svg = d3.select('boby').append('svg'
我是一名优秀的程序员,十分优秀!