我正在阅读 Nicolai M.Josuttis 所写的“The C++ STL. A Tutorial and References”一书,在专门讨论 STL 算法的其中一章中,作者陈述了以下内容: 如果您为列表的元素调用 remove(),则算法不知道它正在对列表进行操作,因此会执行它对任何容器所做的操作:通过更改元素的值来重新排序元素。例如,如果算法删除了第一个元素,则所有后续元素都将分配给它们之前的元素。这种行为与列表的主要优点相矛盾:通过修改链接而不是值来插入、移动和删除元素的能力。为避免性能不佳,列表为所有操作算法提供了特殊的成员函数。你应该总是喜欢它们。此外,这些成员函数确实删除了“已删除”的元素,如下例所示:
#include <list>
#include <algorithm>
using namespace std;
int main()
{
list<int> coll;
// insert elements from 6 to 1 and 1 to 6
for (int i=1; i<=6; ++i) {
coll.push_front(i);
coll.push_back(i);
}
// remove all elements with value 3 (poor performance)
coll.erase (remove(coll.begin(),coll.end(),
3),
coll.end());
// remove all elements with value 4 (good performance)
coll.remove (4);
}
当然,这似乎足以令人信服以供进一步考虑,但无论如何,我决定在我的 PC 上看到运行类似代码的结果,特别是在 MSVC 2013 环境中。这是我的即兴代码:
int main()
{
srand(time(nullptr));
list<int>my_list1;
list<int>my_list2;
int x = 2000 * 2000;
for (auto i = 0; i < x; ++i)
{
auto random = rand() % 10;
my_list1.push_back(random);
my_list1.push_front(random);
}
list<int>my_list2(my_list1);
auto started1 = std::chrono::high_resolution_clock::now();
my_list1.remove(5);
auto done1 = std::chrono::high_resolution_clock::now();
cout << "Execution time while using member function remove: " << chrono::duration_cast<chrono::milliseconds>(done1 - started1).count();
cout << endl << endl;
auto started2 = std::chrono::high_resolution_clock::now();
my_list2.erase(remove(my_list2.begin(), my_list2.end(),5), my_list2.end());
auto done2 = std::chrono::high_resolution_clock::now();
cout << "Execution time while using generic algorithm remove: " << chrono::duration_cast<chrono::milliseconds>(done2 - started2).count();
cout << endl << endl;
}
当看到以下输出时,我很惊讶:
Execution time while using member function remove: 10773
Execution time while using generic algorithm remove: 7459
您能否解释一下这种矛盾行为的原因是什么?