STL containers significantly reduce the complexity of writing code, working with dynamic data structures and, the most important thing, increase its inerrancy. But in some cases, when working with large data items in containers, This technique can produce the inevitable loss of productivity. This is because, that since the operation room a container element, and subsequent displacement elements may require a copy of elements.
Note: The severity of these effects depends on the type of container, and from the transactions. For example, interchange operation 2 elements in the sorting require 3 copyings type container vector and will not require additional copy for container list. But the operation of the initial space in the container (push_back(), insert() and etc.) always make a copy.
This can be a problem for an application, when operations on the containers is critical for runtime (or seem to you such). There are even more complicated cases, when a class container object is not picked up operation, or when the objects are referenced objects themselves, full backups for which you want to perform recursive procedures following all the links (then, in Python, and the other is called a deep copy).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | #include <iostream> #include <vector> #include <algorithm> #include <string> using namespace std; struct data { // запись о студенте string fio; int group, age, scholarship; data(string fio, int group, int age, int scholarship = 0) : fio(fio), group(group), age(age), scholarship(scholarship) { cout << '+'; } data(const data& d) : fio(d.fio), group(d.group), age(d.age), scholarship(d.scholarship) { cout << '+'; } ~data(void) { cout << '-'; } inline friend ostream& operator <<(ostream& out, const data& obj) { return out << "[ " << obj.fio << " : " << obj.group << " : " << obj.age << " : " << obj.scholarship << " ]"; } }; struct comp_data { // функтор сравнения int what; bool compare(const struct data& f, const struct data& s) { switch (abs(what)) { case 1: return f.fio < s.fio; case 2: return f.group < s.group; case 3: return f.age < s.age; case 4: return f.scholarship < s.scholarship; default: return false; } } public: comp_data(int what) : what(what) {} bool operator()(const struct data *f, const struct data *s) { bool ret = compare(*f, *s); return what >= 0 ? ret : !ret; } }; int main(void) { setlocale(LC_ALL, "rus"); struct data list[] = { { "Сидоров С.С.", 12, 19, 1500 }, { "Иванов И.И.", 13, 20 }, { "Петров П.П.", 11, 21 }, { "Чапаев В.И.", 10, 45, 2000 }, }; cout << endl; vector< struct data* > filology; for (unsigned i = 0; i < sizeof(list) / sizeof(list[0]); i++) { filology.push_back(new struct data(list[i])); } cout << endl; while (true) { for (auto x : filology) cout << *x << endl; cout << "поле сортировки? : "; int mode; cin >> mode; if (!cin || (cin.rdstate() & ios::eofbit)) { cout << endl; break; } sort(filology.begin(), filology.end(), comp_data(mode)); } auto i = filology.begin(); while (i != filology.end()) { // filology.clear(); filology.erase(i); } cout << "размер журнала = " << filology.size() << endl; } |
Everything works well, as before - sort a set of records on arbitrary fields and in any order:
(Note, that completing this application you need for Ctrl + D - End Of File ... in the Widows, probably, по Ctrl + Z.)
But! ... Especially debugging "traces" positives were left constructors and destructors records, and recording constructed 8 times, and the destructor is only triggered 4, for local array at the exit point of the block. Local array generally not of interest to us. He was introduced to simplify the example, only as a set of initialization values.
But for the record, placed in a container, records destruction does not occur, and we get a candid memory leak. But worse, after we remove the item from the container (without taking further action), we can not delete the record, calling for it delete. This is because, after call erase() We lost to a record only path through the iterator (the code shows a loop erase(), so graphically, that is equivalent to clear(), the effect of which, It is the same).
Conclusion, which can be made from Example, looks like that:
placing objects in containers not, and Indices on them, can significantly reduce the computational cost of the manipulation (but always principled whether these gains at the current computing power?).
replacement facilities pointers in containers makes the code is much more dangerous in the sense of hidden subtle bugs, And such a serious level, which can further lead to an application crash.
Here some help may have smart pointers of the latest C ++ standard (shared_ptr or weak_ptr, but not unique_ptr and not the good old and problematic auto_ptr), us for this in the previous code, just change 4 strings:
1 2 3 4 5 6 7 | #include <memory> ... bool operator()(const shared_ptr< struct data > f, const shared_ptr< struct data > s){ ... vector< shared_ptr< struct data > > filology; ... filology.push_back(shared_ptr< struct data >(new struct data(list[i]))); |
In Windows, shared_ptr needed #include <memory> , and in other systems, not necessarily.
And application behavior change significantly:
But we should not delude ourselves recklessly, so as smart pointers, removing some, generate other potential concerns (such as cyclic links etc.. about which much is written enough).
Advertising budget and more
Advertising budget and more on Monday mornings
Looking forward to receiving an email from you requesting proof of reading books and magazines and expert books and articles
Bbuyuyuyuyuanpeov od the white house 6