Login | Register   
RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Manage Your STL Container's Storage with Self-swapping Idioms -3 : Page 3




Full Text Search: The Key to Better Natural Language Queries for NoSQL in Node.js

Date: 1/31/2018 @ 2 p.m. ET

Swapping the Right Way
Manual copying is tedious and error-prone. Ideally, you want to perform the trimming operation in a single statement, while avoiding the creation of a dummy container. STL containers define a specialized version of the swap() algorithm as a member function. As a rule, when you have a choice between a generic algorithm and the container's equivalent member function, prefer the latter. Instead of calling

#include <algorithm> std::swap(vi, vi2); //works, but less efficient


vi.swap(vi2); //recommended

The member algorithm is optimized for its container. As such, it's usually more efficient than the generic version.

A final refinement to the design also eliminates the dummy container. Simply swap the container with itself:


Let's see how it works. The expression

vector <int>(vi)

creates a temporary trimmed copy of vi. Then, the swap(vi) call is evaluated, assigning the trimmed temporary to vi, and vice versa. Finally, the temporary object is destroyed.

Here's a modified version of the previous program, now using the swap idiom:

int main() { vector <int> vi; vi.reserve(100); vi.push_back(5); cout<<"capacity before trimming: "<<vi.capacity()<<endl; cout<<"size before trimming: "<<vi.size()<<'\n'<<endl; vector<int>(vi).swap(vi);//trim vi cout<<"capacity after trimming : "<<vi.capacity()<<endl; cout<<"size after trimming : "<<vi.size()<<endl; }

As expected, the output is:

capacity before trimming: 100 size before trimming: 1 capacity after trimming: 1 size after trimming: 1

Emptying a Container
Emptying a container raises a similar problem. The clear() member function destroys the currently stored elements and resets the container's size to 0. However, it doesn't change the container's capacity. Consider:

vi.reserve(100); //enforce a capacity of 100 vi.push_back(5); //size is 1 vi.clear(); //size is 0, but the capacity is unchanged cout<<"capacity: "<<vi.capacity()<<endl; //output: 100 cout<<"size: "<<vi.size()<<'\n'<<endl;//output: 0

To force a container to release both its elements and capacity, use a slightly different version of the swap idiom. Instead of swapping a container with a temporary copy of itself, swap it with an empty temporary:

vector<int>().swap(vi);//sets vi's size and capacity to 0

Danny Kalev is a certified system analyst and software engineer specializing in C++. He was a member of the C++ standards committee between 1997 and 2000 and has since been involved informally in the C++0x standardization process. He is the author of "The ANSI/ISO Professional C++ Programmer's Handbook" and "The Informit C++ Reference Guide: Techniques, Insight, and Practical Advice on C++."
Comment and Contribute






(Maximum characters: 1200). You have 1200 characters left.



Thanks for your registration, follow us on our social networks to keep up-to-date