【发布时间】:2018-02-14 17:46:09
【问题描述】:
我编写了以下字符串连接函数 (join) 来减少分配次数和构造最终字符串所花费的时间。我还想写一个易于使用的附加函数(如果可能的话,单行)。
size_t str_size(const char *str) {
return std::strlen(str);
}
size_t str_size(const std::string &str) {
return str.size();
}
template <typename T>
size_t accumulated_size(const T& last) {
return str_size(last);
}
template <typename T, typename... Args>
size_t accumulated_size(const T& first, const Args& ...args) {
return str_size(first) + accumulated_size(args...);
}
template <typename T>
void append(std::string& final_string, const T &last) {
final_string += last;
}
template <typename T, typename... Args>
void append(std::string& final_string, const T& first, const Args& ...args) {
final_string += first;
append(final_string, args...);
}
template <typename T, typename... Args>
std::string join(const T& first, const Args& ...args) {
std::string final_string;
final_string.reserve(accumulated_size(first, args...));
append(final_string, first, args...);
return std::move(final_string);
}
我使用operator+= 和std::string 类的operator+ 在相当大量的字符串上针对典型的内置C++ 连接功能测试了join 方法。与普通的 operator+= 或 operator+ 方法相比,我的方法如何以及为什么在时间执行方面产生更差的结果?
我正在使用以下类来测量时间:
class timer {
public:
timer() {
start_ = std::chrono::high_resolution_clock::now();
}
~timer() {
end_ = std::chrono::high_resolution_clock::now();
std::cout << "Execution time: " << std::chrono::duration_cast<std::chrono::nanoseconds>(end_ - start_).count() << " ns." << std::endl;
}
private:
std::chrono::time_point<std::chrono::high_resolution_clock> start_;
std::chrono::time_point<std::chrono::high_resolution_clock> end_;
};
我正在比较以下方式:
#define TEST_DATA "Lorem", "ipsum", "dolor", "sit", "ame", "consectetuer", "adipiscing", "eli", "Aenean",\
"commodo", "ligula", "eget", "dolo", "Aenean", "mass", "Cum", "sociis", "natoque",\
"penatibus", "et", "magnis", "dis", "parturient", "monte", "nascetur", "ridiculus",\
"mu", "Donec", "quam", "feli", ", ultricies", "ne", "pellentesque", "e", "pretium",\
"qui", "se", "Nulla", "consequat", "massa", "quis", "eni", "Donec", "pede", "just",\
"fringilla", "ve", "aliquet", "ne", "vulputate", "ege", "arc", "In", "enim", "just",\
"rhoncus", "u", "imperdiet", "", "venenatis", "vita", "just", "Nullam", "ictum",\
"felis", "eu", "pede", "mollis", "pretiu", "Integer", "tincidunt"
#define TEST_DATA_2 std::string("Lorem") + "ipsum"+ "dolor"+ "sit"+ "ame"+ "consectetuer"+ "adipiscing"+ "eli"+ "Aenean"+\
"commodo"+ "ligula"+ "eget"+ "dolo"+ "Aenean"+ "mass"+ "Cum"+ "sociis"+ "natoque"+\
"penatibus"+ "et"+ "magnis"+ "dis"+ "parturient"+ "monte"+ "nascetur"+ "ridiculus"+\
"mu"+ "Donec"+ "quam"+ "feli"+ ", ultricies"+ "ne"+ "pellentesque"+ "e"+ "pretium"+\
"qui"+ "se"+ "Nulla"+ "consequat"+ "massa"+ "quis"+ "eni"+ "Donec"+ "pede"+ "just"+\
"fringilla"+ "ve"+ "aliquet"+ "ne"+ "vulputate"+ "ege"+ "arc"+ "In"+ "enim"+ "just"+\
"rhoncus"+ "u"+ "imperdiet"+ ""+ "venenatis"+ "vita"+ "just"+ "Nullam"+ "ictum"+\
"felis"+ "eu"+ "pede"+ "mollis"+ "pretiu"+ "Integer"+ "tincidunt"
int main() {
std::string string_builder_result;
std::string normal_approach_result_1;
std::string normal_approach_result_2;
{
timer t;
string_builder_result = join(TEST_DATA);
}
std::vector<std::string> vec { TEST_DATA };
{
timer t;
for (const auto & x : vec) {
normal_approach_result_1 += x;
}
}
{
timer t;
normal_approach_result_2 = TEST_DATA_2;
}
}
我的结果是:
- 执行时间:11552 ns(
join方法)。 - 执行时间:3701 ns(
operator+=()方法)。 - 执行时间:5898 ns(
operator+()方法)。
我正在编译:g++ efficient_string_concatenation.cpp -std=c++11 -O3
【问题讨论】:
-
请包括您的测试,包括编译器标志和使用的数据。长期以来,性能 C++ 测试中的性能分析都做得很差。
-
您应该使用 stable_clock,而不是 high_resolution_clock 进行计时。你不是在打开 -O3 的情况下编译吗?
-
我刚刚用 -O3 编译。它实际上有所改进,但仍不比其他方法好。结果:执行时间:8949 ns。 (加入方法),执行时间:3475 ns。 (操作员 += 方法)
-
我不是这方面的专家,但您在 append 函数中使用了递归调用。我的猜测是,与在向量上循环相比,它会影响您的性能
-
避免移动返回的字符串,它会阻止 RVO。参见例如stackoverflow.com/questions/19267408/…
标签: c++ c++11 variadic-templates string-concatenation coding-efficiency