一 起点
老规矩,先上一段代码
class String{
friend std::ostream& operator<<(std::ostream& stream,const String& string);
private:
char* m_buffer;
unsigned int m_size;
public:
String(const char* string){
m_size = strlen(string);
m_buffer = new char[m_size+1];
memcpy(m_buffer,string,m_size+1);
}
String(const String& other):m_size(other.m_size)
{
std::cout<< "copy String"<<std::endl;
m_buffer = new char[m_size+1];
memcpy(m_buffer,other.m_buffer,m_size+1);
}
~String(){
delete[] m_buffer;
}
char& operator[](unsigned int index)
{
return m_buffer[index];
}
};
void PrintString(String& string){
std::cout<<string <<endl;
}
std::ostream& operator<<(std::ostream& stream,const String& string)
{
stream<<string.m_buffer;
return stream;
}
int main(){
std::vector<String> v;
v.push_back("a1");
v.push_back("a2");
// for(String& item : v){
// PrintString(item);
// }
return 0;
}
看到输出
copy String
copy String
copy String
奇怪,这里为什么会有三个日志输出。我一开始想也该只有两个,因为我只 push 了两次数据,第三次是哪儿来的呢?摸索了一番,发现这是 vector 扩容导致,因为 vector 默认容器大小为 1,当我们再 push 第二个数据的时候,它需要创建一个新的容器,然后把之前的数据给拷贝过去。可想而知,当我们的数据量越来越大的时候这得做多少的复制,太浪费性能了。所以这里我们的优化点一就是提前设置容器大小
std::vector<String> v;
v.reserve(2);
v.push_back("a1");
v.push_back("a2");
这样就只会输出两个 copy String 日志。那么这里我们可以进一步做一个优化。
std::vector<String> v;
v.reserve(2);
v.emplace_back("a1");
v.emplace_back("a2");
这样改后,不会再执行任何的拷贝操作了,完美!
emplace_back可以直接在容器中构造新元素,避免了额外的拷贝或移动操作,因此在性能上可能更优。当你需要添加的元素类型有昂贵的拷贝或移动操作时,使用emplace_back是一个更好的选择。push_back需要传递一个与容器元素类型相同的对象,这可能导致额外的拷贝或移动操作。在一些简单类型或者已有对象的情况下,使用push_back也是合适的。
在实际编程中,根据具体情况选择使用 emplace_back 或 push_back。如果性能是关键因素,或者添加的元素类型有昂贵的拷贝或移动操作,那么优先考虑使用 emplace_back。