Exploring the Standard Library Further - Advanced C++ - C++ All-in-One For Dummies (2009)

C++ All-in-One For Dummies (2009)

Book VI

Advanced C++

image

Contents at a Glance

Chapter 1: Exploring the Standard Library Further

Considering the Standard Library Categories

Parsing Strings Using a Hash

Obtaining Information Using a Random Access Iterator

Locating Values Using the Find Algorithm

Using the Random Number Generator

Performing Comparisons Using min and max

Working with Temporary Buffers

Chapter 2: Building Original Templates

Deciding When to Create a Template

Defining the Elements of a Good Template

Creating a Basic Math Template

Building a Structure Template

Developing a Class Template

Considering Template Specialization

Creating a Template Library

Using Your Template Library

Chapter 3: Investigating Boost

Understanding Boost

Obtaining and Installing Boost for CodeBlocks

Using Boost Jam

Using Boost Build

Using Regression

Using Inspect

Understanding BoostBook

Using QuickBook

Using bcp

Using Wave

Building Your First Boost Application Using Date Time

Chapter 4: Boosting up a Step

Parsing Strings Using RegEx

Breaking Strings into Tokens Using Tokenizer

Performing Numeric Conversion

Creating Improved Loops Using Foreach

Accessing the Operating System Using Filesystem

Chapter 1: Exploring the Standard Library Further

In This Chapter

Categorizing the Standard Library functions

Working with container functions such as hash

Performing random access with iterator functions

Working with algorithms such as find

Creating random numbers with functors

Working with utilities such as min and max

Creating temporary buffers with allocators

The Standard Library is one of the most important parts of the C++ developer’s toolkit because it contains a host of interesting functions that let you write great applications. The Standard Library originally started as the Standard Template Library (STL), and a number of companies, including Silicon Graphics, Inc. (SGI) and IBM, distributed it for everyone to use. The International Standards Organization (ISO) eventually took over STL, made a few minor changes to it, and renamed it the Standard Library. Consequently, when you see the STL online, don’t get confused; it’s merely an older version of the Standard Library.

image For the purposes of this book, the differences between the Standard Library and the STL are so small that you can probably use them interchangeably. Just remember that the Standard Library is newer and does contain some changes to make the various versions of the STL work together.

This chapter provides an overview of the Standard Library and shows you some examples of how to use it. However, if you don’t see what you want here, don’t worry, we discuss more examples in later chapters and you can always refer to the Standard Library documentation for additional examples. Before the chapter moves on to any examples, however, it’s important to know what the Standard Library contains, so the first section of this chapter provides you with a list of Standard Library function categories.

Getting a copy of the Standard Library documentation

The Standard Library is incredibly large, so this book doesn’t document it completely. The CodeBlocks product doesn’t come with a Standard Library reference either. However, to really use the Standard Library, you really do need a copy of the documentation.

You can join ISO for a bazillion bucks and get a copy of their document free or purchase a copy of it from http://www.iso.org/iso/iso_catalogue/catalogue_ics/catalogue_detail_ics.htm?csnumber=38110. As an alternative, you can buy a copy of the Standard Library documentation from an ISO member such as the American National Standards Institute (ANSI) for a more reasonable sum. Check it out at http://webstore.ansi.org/RecordDetail.aspx?sku=INCITS%2FISO%2FIEC+14882-2003.

Because the STL and the Standard Library are relatively close, you have a third alternative: use an STL resource. One of the best written and easiest to use resources is from SGI at http://www.sgi.com/tech/stl/. You may also want to review the Tiny STL Primer athttp://www.davethehat.com/articles/tiny_stl.htm for some additional resources (found at the bottom of the Web page).

In addition to the resources mentioned so far, you’ll want to check out Bjarne Stroustrup’s Web site at http://www.research.att.com/~bs/C++.html#standard. Just in case you don’t know, he’s the guy who designed and originally implemented C++. Finally, you can download most of the C++ 1989 standard at ftp://ftp.research.att.com/pub/c++std/WP/CD2/.

Considering the Standard Library Categories

The Standard Library documentation uses a formal approach that you’re going to find difficult to read and even harder to understand; it must have been put together by lawyers more interested in the precise meaning of words rather than the usability of the document. This 748-page tome (in the current version) requires quite a bit of time to review. Fortunately, you don’t have to wade through all that legal jargon mixed indiscriminately with computer jargon and the occasional bit of English. This chapter provides the overview you need to get going quickly.

The best way to begin is to break the Standard Library into smaller pieces. You can categorize the Standard Library functions in a number of ways. One of the most common approaches is to use the following categories:

♦ Containers

♦ Iterators

♦ Algorithms

♦ Functors

♦ Utilities

♦ Adaptors

♦ Allocators

The following sections provide a brief description of each of these categories and tell what you can expect to find in them. Knowing the category can help you locate the function you need quickly on Web sites that use these relatively standard category names.

Containers

Containers work just like the containers in your home — they hold something. You’ve already seen containers at work in other areas of this book. For example, both queues and deques are kinds of containers. The Containers category doesn’t contain any functions, but it does contain a number of types including those in the following table:

basic_string

bit_vector

bitset

char_producer

deque

hash

list

map

multimap

multiset

priority_queue

queue

rope

set

slist

stack

vector

Iterators

Iterators enumerate something. When you create a list of items, and then go through that list checking items off, you’re enumerating the list. Using iterators helps you create lists of items and manipulate them in specific ways. The kind of iterator you create is important because some iterators let you go forward only, some can go in either direction, and some can choose items at random. Each kind of iterator has its specific purpose.

SGI color-coding

The SGI Web site at http://www.sgi.com/tech/stl/stl_index_cat.html uses color-coding to tell you about the content. Here are the categories you’ll see and their associated color:

Concept is red

Type is yellow

Function is green

Overview is purple

The Iterators category includes a number of types. These types determine the kind of iterator you create in your code and the capabilities of that iterator. The following is a list of the iterator types:

back_insert_iterator

bidirectional_iterator

bidirectional_iterator_tag

forward_iterator

forward_iterator_tag

front_insert_iterator

input_iterator

input_iterator_tag

insert_iterator

istream_iterator

iterator_traits

ostream_iterator

output_iterator

output_iterator_tag

random_access_iterator

random_access_iterator_tag

raw_storage_iterator

reverse_bidirectional_iterator

reverse_iterator

sequence_buffer

The Standard Library also includes a number of iterator-specific functions. These functions help you perform tasks such as advance (increment) the iterator by a certain number of positions. You can also measure the distance between the beginning and end of the iterator. The following is a list of iterator functions:

advance

distrance

distance_type

iterator_category

value_type

Algorithms

Algorithms perform data manipulations such as replacing, locating, or sorting information. You’ve already seen some algorithms used in the book because it’s hard to create a substantial application without using one. There aren’t any types in the Algorithms category. The following is a list of algorithm functions:

accumulate

adjacent_difference

adjacent_find

advance

binary_search

copy

copy_backward

copy_n

count

count_if

distance

equal

equal_range

fill

fill_n

find

find_end

find_first_of

find_if

for_each

generate

generate_n

includes

inner_product

inplace_merge

iota

is_heap

is_sorted

iter_swap

lexicographical_compare

lexicographical_compare_3way

lower_bound

make_heap

max

max_element

merge

min

min_element

mismatch

next_permutation

nth_element

partial_sort

partial_sort_copy

partial_sum

partition

pop_heap

power

prev_permutation

push_heap

random_sample

random_sample_n

random_shuffle

remove

remove_copy

remove_copy_if

remove_if

replace

replace_copy

replace_copy_if

replace_if

reverse

reverse_copy

rotate

rotate_copy

search

search_n

set_difference

set_intersection

set_symmetric_difference

set_union

sort

sort_heap

stable_partition

stable_sort

swap

swap_ranges

transform

uninitialized_copy

uninitialized_copy_n

uninitialized_fill

uninitialized_fill_n

unique

unique_copy

upper_bound

Functors

Functors are a special class of object that acts as if it’s a function. You call a functor using the same syntax that you use for a function in most cases, but functors possess all the good elements of objects as well. Functors come in a number of forms. For example, a binary function functor accepts two arguments as input and provides a result as output. Functors include a number of types that determine the kind of function the code creates, as shown in the following table:

binary_compose

binary_function

binary_negate

binder1st

binder2nd

divides

equal_to

greater

greater_equal

hash

identity

less

less_equal

logical_and

logical_not

logical_or

mem_fun1_ref_t

mem_fun1_t

mem_fun_ref_t

mem_fun_t

minus

modulus

multiplies

negate

not_equal_to

plus

pointer_to_binary_function

pointer_to_unary_function

project1st

project2nd

select1st

select2nd

subtractive_rng

unary_compose

unary_function

unary_negate

The Functors category contains only one function, ptr_fun. This function accepts a function pointer as input and outputs a function pointer adapter, which is a kind of function object. You use ptr_fun when you need to pass a function as input to another function such astransform. Here is an example of such code:

#include <iostream>

#include <math.h>

#include <ext/functional>

using namespace std;

using namespace __gnu_cxx;

int main()

{

const int N = 10;

double A[N];

fill(A, A+N, 100);

cout << A[0] << endl;

transform(A, A+N, A, compose1(negate<double>(), ptr_fun(fabs)));

cout << A[0] << endl;

return 0;

}

This example begins by creating a constant that determines the number of elements in the array A. The code then fills every element in A with the value 100 and displays just one of those elements on screen.

The tricky part comes next. The transform algorithm accepts the beginning of an input iterator, the end of an input iterator, and output iterator, and the transformation you want to perform. The transform algorithm takes each of the values in the input iterator, performs the transformation you requested, and places the result in the output iterator.

In this case, the code uses the nonstandard SGI functor compose1, which takes two adaptable unary functions as input. Because fabs is a standard function, you must use ptr_fun to change it into a function pointer adapter before you can use it with compose1. The result is that Acontains the negation of the absolute value of the original value in A or -100 when the transformation is complete.

image The GNU gcc compiler supports a number of STL features that don’t appear as part of the Standard Library. In this case, compose1 appears in the ext/functional header, so you must provide the #include <ext/functional> line of code. In addition, becausecompose1 is nonstandard, it appears as part of a different namespace. Consequently, you must also provide the using namespace __gnu_cxx; line of code to access the functor without having to precede it with the namespace information.

image Many C++ examples rely on the nonstandard parts of STL to perform tasks. If you want maximum compatibility and transportability for your code, you should avoid these nonstandard features.

Utilities

Utilities are functions and types that perform small service tasks within the Standard Library. The functions are min, max, and the relational operators. The types are chart_traits (the traits of characters used in other Standard Library features, such as basic_string) and pair (a pairing of two heterogeneous values).

Adaptors

Adapters perform conversions of a sort. They make it possible to adapt one kind of data to another. In some cases, adaptors perform data conversion, such as negating numbers. The Adaptors category includes one function, ptr_fun, which is explained in the “Functors” section of the chapter. In addition, the Adaptors category includes the types shown in the following table:

back_insert_iterator

binary_compose

binary_negate

binder1st

binder2nd

front_insert_iterator

insert_iterator

mem_fun1_ref_t

mem_fun1_t

mem_fun_ref_t

mem_fun_t

pointer_to_binary_function

pointer_to_unary_function

priority_queue

queue

raw_storage_iterator

reverse_bidirectional_iterator

reverse_iterator

sequence_buffer

stack

unary_compose

unary_negate

Allocators

Allocators manage resources, normally memory. In most cases, you won’t ever need to use the members of the Allocators category. For example, you normally create new objects using the new operator. The new operator allocates memory for the object and then creates it by calling the object’s constructor. In rare cases, such as when you want to implement a form of object pooling, you may want to separate the memory allocation process from the construction process. In this case, you call construct to perform the actual task of construction the object based on its class definition. The Allocators category has the following functions.

construct

destroy

get_temporary_buffer

return_temporary_buffer

uninitialized_copy

uninitialized_copy_n

uninitialized_fill

uninitialized_fill_n

The Allocators category also includes a couple of types. These types help you manage memory, and you may find more use for them than you will the functions in this category. The types are

raw_storage_iterator

temporary_buffer

Parsing Strings Using a Hash

Hashes are an important security requirement for applications today. A hash creates a unique numeric equivalent of any string you feed it. Theoretically, you can’t duplicate the number the hash creates by using another string. A hash isn’t reversible — it isn’t the same as encryption and decryption.

A common use for hashes is to send passwords from a client to a server. The client converts the user’s password into a numeric hash and sends that number to the server. The server verifies the number, not the password. Even if people are listening in, they have no way to ascertain the password from the number and therefore can’t steal the password for use with the target application.

Unfortunately, hashes are part of the STL but not part of the Standard Library. However, hashes are so important that you really do need to know how to use them. As with the ptr_fun example shown in the “Functors” section of the chapter, you need to do a little extra work to make hashes work with CodeBlocks, as shown in the following example:

#include <iostream>

#include <ext/hash_set>

using namespace std;

using namespace __gnu_cxx;

int main()

{

hash<const char*> MyHash;

cout << “The hash of \”Hello World\” is:” << endl;

cout << MyHash(“Hello World”) << endl;

cout << “while the hash of \”Goodbye Cruel World\” is:” << endl;

cout << MyHash(“Goodbye Cruel World”) << endl;

return 0;

}

The example begins by creating a hash function object, MyHash. You use this function object to convert input text to a hash value. The function object works just like any other function, so you might provide the input text as MyHash(“Hello World”). Hashes always output precisely the same value given a particular input. Consequently, you should see the following output from this example.

The hash of “Hello World” is:

952921740

while the hash of “Goodbye Cruel World” is:

1126809588

Hashes have uses other than security requirements. For example, you can create a container that relies on a hash to make locating a particular value easier. In this case, you use a key/value pair in a hash map. The following code shows how to create a hash map:

#include <iostream>

#include <ext/hash_map>

using namespace std;

using namespace __gnu_cxx;

struct eqstr

{

bool operator()(const char* s1, const char* s2) const

{

return strcmp(s1, s2) == 0;

}

};

int main()

{

hash_map<const char*, int, hash<const char*>, eqstr> Colors;

Colors[“Blue”] = 1;

Colors[“Green”] = 2;

Colors[“Teal”] = 3;

Colors[“Brick”] = 4;

Colors[“Purple”] = 5;

Colors[“Brown”] = 6;

Colors[“LightGray”] = 7;

cout << “Brown = “ << Colors[“Brown”] << endl;

cout << “Brick = “ << Colors[“Brick”] << endl;

// This key isn’t in the hash map, so it returns a

// value of 0.

cout << “Red = “ << Colors[“Red”] << endl;

return 0;

}

A hash map requires four inputs:

♦ Key type

♦ Data type

♦ Hashing function

♦ Equality key

The first three inputs are straightforward. In this case, the code uses a string as a key type, an integer value as a data type, and hash<const char*> as the hashing function. You already know how the hashing function works from the previous example in this section.

The equality key class is a little more complex. You must provide the hash map with a means of determining equality. In this case, the code compares the input string with the string stored as the key. The eqstr structure performs the task of comparing the input string to the key. The structure must return a Boolean value, so the code compares the strcmp function to 0. When the two are equal, meaning the strings are equal, eqstr returns true.

image The example goes on to check for three colors, only two of which appear in the hash map Colors. In the first two cases, you see the expected value. In the third case, you see 0, which indicates that Colors doesn’t contain the desired key. Always reserve 0 as an error indicator when using a hash map because the hash map will always return a value, even if it doesn’t contain the desired key.

Standard Library versus STL headers

You’ll find a wealth of STL examples on the Internet because STL was around for a long time before the Standard Library appeared. In fact, some developers continue to prefer the STL simply because they’re familiar with it. Here’s a little secret: The STL headers use a .h extension and the Standard Library headers don’t have an extension. For example, the now familiar iostream header used in every previous example in the book is actually the Standard Library form — the STL form is iostream.h.

Here’s another secret. The Standard Library headers often call on the STL headers, so you’ve also been using STL throughout the book. It’s amazing to see how these things work out.

Obtaining Information Using a Random Access Iterator

Most containers let you perform random access of data they contain. For example, the following code shows that you can create an iterator and then add to or subtract from the current offset to obtain values within the container that iterator supports:

#include <iostream>

#include <vector>

using namespace std;

int main()

{

vector<string> Words;

Words.push_back(“Blue”);

Words.push_back(“Green”);

Words.push_back(“Teal”);

Words.push_back(“Brick”);

Words.push_back(“Purple”);

Words.push_back(“Brown”);

Words.push_back(“LightGray”);

// Define a random iterator.

vector<string>::iterator Iter = Words.begin();

// Access random points.

Iter += 5;

cout << *Iter << endl;

Iter -= 2;

cout << *Iter << endl;

return 0;

}

In this case, the vector, Words, contains a list of seven items. The code creates an iterator for Words named Iter. It then adds to or subtracts from the iterator offset and displays the output on screen. Here is what you see when you run this example:

Brown

Brick

Sometimes you need to perform a special task using a random access iterator. For example, you might want to create a special function to summate the members of vector or just a range of members within vector. In this case, you must create a specialized function to perform the task as follows because the Standard Library doesn’t include any functions to do it for you:

#include <iostream>

#include <vector>

using namespace std;

template <class RandomAccessIterator>

float AddIt(RandomAccessIterator begin, RandomAccessIterator end)

{

float Sum = 0;

RandomAccessIterator Index;

// Make sure that the values are in the correct order.

if (begin > end)

{

RandomAccessIterator temp;

temp = begin;

begin = end;

end = temp;

}

for (Index = begin; Index != end; Index++)

Sum += *Index;

return Sum;

}

int main()

{

vector<float> Numbers;

Numbers.push_back(1.0);

Numbers.push_back(2.5);

Numbers.push_back(3.75);

Numbers.push_back(1.26);

Numbers.push_back(9.101);

Numbers.push_back(11.3);

Numbers.push_back(1.52);

// Sum the individual members.

float Sum;

Sum = AddIt(Numbers.begin(), Numbers.end());

cout << Sum << endl;

Sum = AddIt(Numbers.end(), Numbers.begin());

cout << Sum << endl;

// Sum a range.

vector<float>::iterator Iter = Numbers.begin();

Iter += 5;

Sum = AddIt(Iter, Numbers.end());

cout << Sum << endl;

return 0;

}

This example builds on the previous example. You still create vector, Numbers, and fill it with data. However, in this case, you create an output variable, Sum, that contains the summation of the elements contained in Numbers.

AddIt is a special function that accepts two RandomAccessIterator values as input. These two inputs represent a range within the vector that you want to manipulate in some way. The example simply adds them, but you can perform any task you want. The output is a floatthat contains the summation.

AddIt works as you expect. You call it as you would any other function and provide a beginning point and an end point within vector. The first two calls to AddIt sum the entire vector, while the third creates an iterator, changes its offset, and then sums a range withinvector. Here is the output from this example:

30.431

30.431

12.82

image A random access iterator can go in either direction. In addition, you can work with individual members within the container supplied to iterator. As a result, the functions you create for iterator must be able to work with the inputs in any order. How you handle this requirement depends on the kind of function you create.

Locating Values Using the Find Algorithm

The Standard Library contains a number of functions to find something you need within a container. Locating what you need as efficiently as possible is always a good idea. Unlike your closet, you want your applications well organized and easy to manage! The four common findalgorithms are

♦ find

♦ find_end

♦ find_first_of

♦ find_if

The algorithm you use depends on what you want to find and where you expect to find it. You’ll likely use the plain find algorithm most often. The following example shows how to locate a particular string within vector — you can use the same approach to locate something in any container type:

#include <iostream>

#include <vector>

#include <algorithm>

using namespace std;

int main()

{

vector<string> Words;

Words.push_back(“Blue”);

Words.push_back(“Green”);

Words.push_back(“Teal”);

Words.push_back(“Brick”);

Words.push_back(“Purple”);

Words.push_back(“Brown”);

Words.push_back(“LightGray”);

vector<string>::iterator Result =

find(Words.begin(), Words.end(), “LightGray”);

if (Result != Words.end())

cout << *Result << endl;

else

cout << “Value not found!” << endl;

Result = find(Words.begin(), Words.end(), “Black”);

if (Result != Words.end())

cout << *Result << endl;

else

cout << “Value not found!” << endl;

}

The example starts with vector containing color strings. In both cases, the code attempts to location a particular color within vector. The first time the code is successful because LightGray is one of the colors listed in vector. However, the second attempt is thwarted becauseBlack isn’t one of the colors in vector. Here’s the output from this example:

LightGray

Value not found!

image Never assume that the code will find a particular value. Always assume that someone is going to provide a value that doesn’t exist and then provide a means of handling the nonexistent value. In this example, you simply see a message stating the value wasn’t found. However, in real-world code, you often must react to situations where the value isn’t found by

♦ Indicating an error condition

♦ Adding the value to the container

♦ Substituting a standard value

♦ Defining an alternative action based on invalid input

imageThe find algorithm is a personal favorite because it’s so flexible. You can use it for external and internal requirements. Even though the example shows how you can locate information in an internal vector, you can also use find for external containers, such as disk drives. Have some fun with this one — experiment with all the containers you come across.

Using the Random Number Generator

Random number generators fulfill a number of purposes. Everything from games to simulations require a random number generator to work properly. Randomness finds its way into business what-if scenarios as well. In short, you need to add random output to your application in many situations.

Creating a random number isn’t hard. All you need to do is call a random number function as shown in the following code:

#include <iostream>

using namespace std;

int main()

{

// Always set a seed value.

srand((unsigned int)time(NULL));

int RandomValue = rand() % 12;

cout << “The random month number is: “ << RandomValue + 1 << endl;

return 0;

}

image Actually, none of the random number generators in the Standard Library works properly — imagine that! Every random number generator is a pseudorandom number generator. The numbers are distributed such that it appears that you see a random sequence, but given enough time and patience, the sequence repeats. In fact, if you don’t set a seed value for your random number generator, you can obtain predictable sequences of numbers every time. How boring.

imageThe first line of code in main sets the seed by using the system time. Using the system time ensures a certain level of randomness in the starting value and, therefore, a level of randomness for your application as a whole. If you comment out this line of code, you see the same output every time you run the application. In our case, our system output 6 every time.

The example application uses rand to create the random value. When you take the modulus of the random number, you obtain an output that is within a specific range, 12 in this case. The example ends by adding 1 to the random number because there isn’t any month 0 in the calendar, and then outputs the month number for you.

The Standard Library provides access to two types of pseudorandom number generators. The first type requires that you set a seed value. The second type requires that you provide an input value with each call and doesn’t require a seed value. Each outputs a different data type, so you can choose the kind of random number you obtain. Table 1-1 lists the random number generators and tells you what data type they output.

Table 1-1 Pseudorandom Number Generator Functions

Function

Output Type

Seed Required?

rand

integer

yes

drand48

double

yes

erand48

double

no

lrand48

long

yes

nrand48

long

no

mrand48

signed long

yes

jrand48

signed long

no

Now that you know about the pseudorandom number generators, look at the seed functions used to prime them. Table 1-2 lists the seed functions and their associated pseudorandom number generator functions.

Table 1-2 Seed Functions

Function

Associated Pseudorandom Number Generator Function

srand

rand

srand48

drand48

seed48

mrand48

lcong48

lrand48

Performing Comparisons Using min and max

Computer programs perform many comparisons. In most cases, you don’t know what the values are in advance or you wouldn’t be interested in performing the comparison in the first place. The min and max functions make it possible to look at two values and determine the minimum or maximum value. Here’s how you use these two functions:

#include <iostream>

using namespace std;

int main()

{

int Number1, Number2;

cout << “Type the first number: “;

cin >> Number1;

cout << “Type the second number: “;

cin >> Number2;

cout << “The minimum number is: “ << min(Number1, Number2) << endl;

cout << “The maximum number is: “ << max(Number1, Number2) << endl;

return 0;

}

In this case, the code accepts two numbers as input and then compares them using min and max. The output you see depends on what you provide as input, but the first output line tells you which number is smaller and the second tells you which is larger.

Working with Temporary Buffers

Temporary buffers are useful for all kinds of tasks. Normally, you use them when you want to preserve the original data, yet you need to manipulate the data in some way. For example, creating a sorted version of your data is a perfect use of a temporary buffer. The following example shows how to use a temporary buffer to sort some strings.

#include <iostream>

#include <vector>

#include <memory>

using namespace std;

int main()

{

vector<string> Words;

Words.push_back(“Blue”);

Words.push_back(“Green”);

Words.push_back(“Teal”);

Words.push_back(“Brick”);

Words.push_back(“Purple”);

Words.push_back(“Brown”);

Words.push_back(“LightGray”);

int Count = Words.size();

cout << “Words contains: “ << Count << “ elements.” << endl;

// Create the buffer and copy the data to it.

pair<string*, ptrdiff_t> Mem = get_temporary_buffer<string>(Count);

uninitialized_copy(Words.begin(), Words.end(), Mem.first);

// Perform a sort and display the results.

sort(Mem.first, Mem.first+Mem.second);

for (int i = 0; i < Mem.second; i++)

cout << Mem.first[i] << endl;

return 0;

}

The example starts with the now familiar list of color names. It then counts the number of entries in vector and displays the count on screen.

At this point, the code creates the temporary buffer using get_temporary_buffer. The output is pair, with the first value containing a pointer to the string values and the second value containing the count of data elements. Mem doesn’t contain anything — you have simply allocated memory for it.

The next task is to copy the data from vector (Words) to pair (Mem) using uninitialized_copy. Now that Mem contains a copy of your data, you can organize it using the sort function. The final step is to display the Mem content on screen. Here is what you’ll see:

Words contains: 7 elements.

Blue

Brick

Brown

Green

LightGray

Purple

Teal