我使用此代码运行了一些测试(使用 Visual Studio 2019),并观察到调试和发布版本的行为差异。调试构建 DO 调用复制构造函数并且不执行 RVO/复制省略。发布版本会进行优化,并且不会进行不必要的复制。此示例向您展示如何以最少的复制(在发布版本中)拆分字符串
这个结果确实让我有些吃惊,所以感谢您提出这个问题。我今天确实学到了一些东西:)
发布版本的输出与预期一致(emplace_back 也不复制):
-----------------------------------------------------
calling split function
my_list::my_list
my_string::my_string
my_string::my_string
my_string::my_string
my_string::my_string
-----------------------------------------------------
result of split
the
quick
brown
fox
-----------------------------------------------------
cleanup vector starting
my_list::~my_list
my_string::~my_string
my_string::~my_string
my_string::~my_string
my_string::~my_string
但是调试版本显然没有进行这种优化:
my_list::my_list
my_string::my_string
my_string::my_string
my_string::my_string
my_string::my_string
my_string::my_string(const my_string&), copy constructor
my_string::my_string(const my_string&), copy constructor
my_string::my_string(const my_string&), copy constructor
my_string::my_string(const my_string&), copy constructor
my_list::my_list(const my_list&), copy constructor
my_list::~my_list
my_string::~my_string
my_string::~my_string
my_string::~my_string
my_string::~my_string
-----------------------------------------------------
result of split
the
quick
brown
fox
-----------------------------------------------------
cleanup vector starting
my_list::~my_list
my_string::~my_string
my_string::~my_string
my_string::~my_string
my_string::~my_string
这是测试代码:
#include <iostream>
#include <vector>
struct my_string
{
my_string(const char* from, const char* to) :
value(from, to)
{
std::cout << " my_string::my_string\n";
}
my_string(const my_string& rhs) :
value{ rhs.value }
{
std::cout << " my_string::my_string(const my_string&), copy constructor\n";
}
my_string(my_string&& rhs) :
value{ std::move(rhs.value) }
{
std::cout << " my_string::my_string(my_string&&), move constructor\n";
}
~my_string()
{
std::cout << " my_string::~my_string\n";
}
std::string value;
};
struct my_list
{
my_list()
{
// note reserving some more room up front will reduce reallocations
// try commenting this out and you will see many more strings created/destroyed
// because of vector reallocation
strings.reserve(128);
std::cout << "my_list::my_list\n";
}
my_list(const my_list& rhs) :
strings{ rhs.strings }
{
std::cout << "my_list::my_list(const my_list&), copy constructor\n";
}
~my_list()
{
std::cout << "my_list::~my_list\n";
}
std::vector<my_string> strings;
};
my_list split(const char* string, char delim)
{
my_list list;
for (const char* ps = string; *ps != 0; ++ps)
{
const char* pe{ ps };
while ((*pe != 0) && (*pe != delim))
{
++pe;
}
list.strings.emplace_back(ps,pe);
ps = pe;
}
return list;
}
int main()
{
std::cout << "-----------------------------------------------------\n";
std::cout << "calling spit function\n\n";
{
auto mylist = split("the,quick,brown,fox", ',');
std::cout << "-----------------------------------------------------\n";
std::cout << "result of split \n\n";
for (const auto& mystring : mylist.strings)
{
std::cout << mystring.value << "\n";
}
std::cout << "\n-----------------------------------------------------\n";
std::cout << "cleanup vector starting";
}
}