![](/img/trans.png)
[英]Why is there no emplace or emplace_back for std::string?
[英]Why emplace_back does matter?
#include <iostream>
#include <vector>
struct T{
T(){
std::cout << "Constructor\n";
}
~T(){
std::cout << "Destructor\n";
}
};
int main() {
std::vector<T> vec;
vec.push_back(T());
vec.push_back(T());
return 0;
}
输出为:
(1)Constructor
(2)Destructor
(3)Constructor
(4)Destructor
(5)Destructor
(6)Destructor
(7)Destructor
为什么有如此多的节制调用? 我看到:
(1)构建临时对象temp1
(2)破坏temp1
(3)构造临时对象temp2
(4)破坏temp2
然后,它被称为temp1和temp 2的复制构造函数或move构造函数。因此,(5)和(6)很清楚。 但是(7)呢?
让我们扩展一下结构:
struct T {
T() {
std::cout << "Constructor\n";
}
T(const T&) {
std::cout << "Copy Constructor\n";
}
T(T&&) {
std::cout << "Move Constructor\n";
}
~T() {
std::cout << "Destructor\n";
}
};
并分别调用push_back
方法:
vec.push_back(T()); // 1
std::cout << "--- --- ---\n";
vec.push_back(T()); // 2
std::cout << "--- --- ---\n";
现在输出看起来更加完整:
Constructor
Move Constructor
Destructor
--- --- ---
Constructor
Move Constructor
Copy Constructor
Destructor
Destructor
--- --- ---
Destructor
Destructor
第一组:
Constructor
Move Constructor
Destructor
对应于第一个push_back
调用:
vec.push_back(T()); // 1
输出可能很容易解密:
Constructor // Create a temporary
Move Constructor // Move a temporary into the internal vector storage
Destructor // Destroy a temporary
第二组:
Constructor
Move Constructor
Copy Constructor
Destructor
Destructor
对应于第二个push_back
调用:
vec.push_back(T()); // 2
稍微复杂一点:
Constructor // create a temporary
Move Constructor // move it into the newly allocated vector storage
Copy Constructor // copy previously created element into the new storage
Destructor // destroy old storage
Destructor // destroy temporary
在这里您应该记住, 向量类在内部分配其内存,然后对其进行管理以为所有元素提供足够的空间。 因此,如果添加更多元素,则会发生新分配,并且会将旧元素复制或移动到新存储中。
在已知大小的情况下,您可以使用reserve
方法,该方法只是为特定数量的元素保留足够的内存。 它允许避免在将新元素添加到向量中(至少直到不超过保留大小)的情况下,在这些重新分配期间避免不必要的内存重新分配和复制或移动元素。
第三组:
Destructor
Destructor
对应于程序结尾处的向量 vec
析构函数调用。
emplace_back对于“仅移动”类型(例如std :: unique_ptr)很重要。
这是错误的,并且过于简单。 并非所有容器均被平等地创建。 对于您的向量示例,如果我们使用reserve
则实现可以执行移动分配而不是构造,从而消除了我们的复制/外部析构函数:
std::vector<T> v;
v.reserve(2);
v.emplace_back(1);
v.emplace_back(1);
输出:
Constructor
Constructor
---
Destructor
Destructor
对于一组:
std::set<T> s;
s.emplace(1);
s.emplace(1);
我们得到相同的输出。 为什么呢 集合在理论上应该只构造一个对象,因为集合是唯一的对吗? 实际上,典型的实现会构造一个临时节点以执行比较,即使它从未进入容器也要考虑额外的构造/破坏。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.