Using the STL in C++Builder VCL Applications
我说要有光2010/04/19软件综合 IP:北京
By: Charles Calvert

Abstract: This simple article is designed to show that you can combine the C++ Standard Template Library in any way you want with the C++Builder Visual Component Library.

Using the STL in C++Builder VCL Applications

Copyright (c) 1998 by Charlie Calvert

First Published: Dec 11, 1998

This simple article is designed to show that you can combine the C++ Standard Template Library in any way you want with the C++Builder Visual Component Library. In particular, I give brief examples showing the use of the list, queue, stack, set, and vector STL template classes in a VCL based program.

I've created this article for three different reasons:

XXXXople sometimes directly ask me: "Can you use the STL in a C++Builder GUI based appliction?" The answer to that question is yes, and this article shows how to do it.
XXXXe second reason is actually a bit political. When some developers see the visual design tools in C++Builder they incorrectly assume that a tool this easy to use can't really be a C++ compiler. Well, C++Builder is a real C++ compiler, and a good one at that! This article makes that point by giving the highly technical STL a light work out inside a standard C++Builder application. My point, of course, is not that the STL is hard to use, for it is not. Rather, my point is that the STL is hard to compile, and yet C++Builder rips right through all that tricky C++ code in a flash.
XXXX provide a very short, very high level, review, reference, or introduction to the STL.
The primary purpose of this article is to show that the STL compiles fine inside C++Builder. In the process I provide a lightweight introduction to the STL. If you've never used the STL before, or want a quick refresher course on the subject, you will probably find this article useful.

I'm not suggesting that you necessarily should use the STL in lieu of the simpler TStringList and TList classes that are built into the VCL. In fact, if you are new to programming, or if you are only a part time C++ developer, then I suggest using the elegant TStringList and TList classes. However, if you are a C++ guru, then of course you realize that the STL is not only a stunning pyrotechnic effect, but also a genuinely useful tool when placed in the right hands.

I should perhaps add that one of the main goals of C++Builder 4 is to bring the compiler up to speed with the final draft of the C++ standard, particularly in regard to its template support. There are few small holes in our template support in CBuilder 3.0, but they should all be plugged when CBuilder 4.0 ships.

Erik Jakowatz provided some technical assistance with portions of this article. Thank you Erik!

What is the STL?
The C++ language allows you to use object oriented programming to create new types that behave in radical and unique ways. Other languages, such as Object Pascal, usually need to make changes to the compiler itself before they can effect similar syntactical accomplishments. For instance, in Object Pascal, the string type is implemented in the compiler, while C++ creates a similar type simply by defining a powerful new class.

The STL is a set of classes that create new types and a set of related classes and function for acting on those types. Most of these types are containers, such as stacks, queues, linked lists, and sets.

STL containers use template syntax to ensure that can store and manipulate virtually any type or class. Templates are a special type of class that can operate on a wide variety of types. If you build a regular array class, then it can probably only with one type of variable, for instance, it can be an array of strings, or an array of integers. Template classes are more flexible, in that a single template array class can work with a variety of types of such as strings, integers, floats, other classes, etc.

The STL is not a third party library. It is a set of classes that make up a part of the C++ language. The STL is part of the standard C++ library.

Understanding the Example Programs

Two example programs, called ListStuff.dpr and MoreListStuff accompany this article. The ListStuff program is a simple CBuilder form with a series of buttons on it, as shown in Figure 1. The MoreListStuff program, shown in Figure 2, is a superset of the ListStuff example that contains many more examples of how to use the STL.


Figure 1: The first example program that accompanies this article.


Figure 2: The MoreListStuff program provides numerous examples of how to use key features of the STL.

If you select menu or button options in either program, then a few lines of C++ code that use the STL will be executed.

At the top of the source for the main form of each program, I have #included a series of header files that enable you to use the STL in that particular module:

#include <list>
#include <string>
#include <vector>
#include <queue>
#include <set>
#include <stack>
#include <iostream.h>
#include <fstream.h>
Noticing that you don't write #include <vector.h>, but instead write #include <vector>.

The string header allows you to use the C++ String class, and the vector headers allow you to use the C++ Vector class, and so on. In general, you will need to include iostream.h in all the STL programs you create. I also include fstream in order to provide some brief examples of streaming.

The complete listing for the main form of the ListStuff program is shown below in Listings 1 and 2. I do not include the complete listing for the MoreListStuff program in this paper because it is long and unwieldy. In general, I created the ListStuff program to give you an easy to parse and work with subset of the MoreListStuff program.

Listing 1: The header for the main form of the ListStuff application.


///////////////////////////////////////
// File: Main.h
// Project: ListStuff.dpr
// Creator: Copyright 1998 by Charlie Calvert
//
//---------------------------------------------------------------------------

#ifndef MainH #define MainH
//---------------------------------------------------------------------------

#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>

//---------------------------------------------------------------------------

class TForm1 : public TForm
{
  __published:
  TButton *ListBtn;
  TButton *VectorBtn;
  TListBox *ListBox1;
  TButton *QueueBtn;
  TButton *SetBtn;
  TButton *StackBtn;
  TButton *AlgorithmBtn;
  void __fastcall ListBtnClick(TObject *Sender);
  void __fastcall VectorBtnClick(TObject *Sender);
  void __fastcall QueueBtnClick(TObject *Sender);
  void __fastcall SetBtnClick(TObject *Sender);
  void __fastcall StackBtnClick(TObject *Sender);
  void __fastcall AlgorithmBtnClick(TObject *Sender);
private:

public:
__fastcall TForm1(TComponent* Owner);
};

//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------

#endif  
Listing 1: The source for the main form of the ListStuff application.
///////////////////////////////////////
// File: Main.cpp
// Project: ListStuff.dpr
// Creator: Copyright (c) 1998 by Charlie Calvert
//
//---------------------------------------------------------------------------

#include <vcl.h>
#include <list>
#include <string>
#include <vector>
#include <queue>
#include <set>
#include <stack>
#include <iostream.h>
#include <fstream.h>
#include <dir.h>
#pragma hdrstop
#include "Main.h"

//---------------------------------------------------------------------------

#pragma package(smart_init)
#pragma resource "*.dfm"

TForm1 *Form1;

//---------------------------------------------------------------------------

__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}

//---------------------------------------------------------------------------

void __fastcall TForm1:[s:10]istBtnClick(TObject *Sender)
{
  list<string, allocator<string> > MyList;
  struct ffblk FindBlock;
  list<string, allocator<string> >::iterator MyIterator;
  int done = findfirst("*.*", &FindBlock, 0);
  
  while (!done)
  {
    XXXXXXXXXsert(XXXXXXXXXgin(), FindBlock.ff_name);
    done = findnext(&FindBlock);
  }
  ListBox1->Clear();
  
  for (MyIterator = XXXXXXXXXgin(); MyIterator != MyList.end(); MyIterator++)
  {
    string S = *MyIterator;
    ListBox1->Items->Add(S.c_str());
  }
  
  ofstream
  ofs("foo.dat");
  
  for (MyIterator = XXXXXXXXXgin(); MyIterator != MyList.end(); MyIterator++)
  {
    ofs << *MyIterator << endl;
  }
  
  ifstream ifs("Foo.dat");
  string S;
  ifs >> S;
  
  ListBox1->Items->Add("From a stream: " + AnsiString(S.c_str()));
}

//---------------------------------------------------------------------------

void __fastcall TForm1::VectorBtnClick(TObject *Sender)
{
  vector<int> MyVector;
  int i;
  
  for (i = 0; i < 25; i++)
    XXXXXXXXXXXsert(MyVector.end(), i);
  
  ListBox1->Clear();
  
  for (i = 0; i < XXXXXXXXXXXze(); i++)
  {
    int j = MyVector[i];
    ListBox1->Items->Add(IntToStr(j));
  }
}

//---------------------------------------------------------------------------

void __fastcall TForm1:[s:11]ueueBtnClick(TObject *Sender)
{
  queue<int> MyQueue;
  
  MyQueue.push(5);
  MyQueue.push(6);
  MyQueue.push(7);

  ListBox1->Clear();
  
  int i = XXXXXXXXXXont();

  ListBox1->Items->Add("Front: " + IntToStr(i));
  i = XXXXXXXXXXck();
  
  ListBox1->Items->Add("Back: " + IntToStr(i));
}

//---------------------------------------------------------------------------
void __fastcall TForm1::SetBtnClick(TObject *Sender)
{

  set<int> MySet;
  set<int>::iterator MyIterator;

  int i;
  for (i = 1; i <= 10; ++i)
    XXXXXXXXsert(i);

  MyIterator = XXXXXXXXgin();
  i = *MyIterator;

  ListBox1->Clear();
  ListBox1->Items->Add("First element in set: " + IntToStr(i));
  ListBox1->Items->Add("");
  
  ListBox1->Items->Add("The whole set: ");

  for (XXXXXXXXgin(); MyIterator != MySet.end(); MyIterator++)
    ListBox1->Items->Add(IntToStr(*MyIterator));
}

//---------------------------------------------------------------------------
void __fastcall TForm1::StackBtnClick(TObject *Sender)
{
  stack<int> MyStack;
  ListBox1->Clear();

  ListBox1->Items->Add("[s:9]ushing 5 on to the stack");

  MyStack.push(5);
  int i = XXXXXXXXXXp();

  ListBox1->Items->Add("Checking top item on stack: " + IntToStr(i));
  ListBox1->Items->Add("Adding four items to stack");
  
  for (i = 0; i <= 4; i ++)
    MyStack.push(i);

  MyStack.pop();
  i = XXXXXXXXXXp();

  ListBox1->Items->Add("[s:9]opping item from stack: " + IntToStr(i));
  
  MyStack.pop();
  i = XXXXXXXXXXp();

  ListBox1->Items->Add("[s:9]opping item from stack: " + IntToStr(i));
}

//---------------------------------------------------------------------------

void __fastcall TForm1::AlgorithmBtnClick(TObject *Sender)
{
  int MyArray[6] = {1, 2, 3, 4, 5, 6};
  AnsiString ValueAsString;
  
  if (InputQuery("Enter a number between 1 and 6", "Number", ValueAsString))
  {
    int ValueToFind = StrToInt(ValueAsString);
    int *ValueFound = find(&MyArray[0], &MyArray[6], ValueToFind);
    ListBox1->Clear();
    
    if (!(ValueFound == &MyArray[6]))
      ListBox1->Items->Add("Value found: " + IntToStr(*ValueFound));
    else
      ListBox1->Items->Add("Value not found");
  }
}

//---------------------------------------------------------------------------
Those who are not familiar with the C++Builder will perhaps be curious about the reference to vcl.h at the top of Listing 2. The VCL is a class library, very similar to OWL or MFC, that allows users to create components. VCL Components are classes that can be manipulated visually with the mouse.

A VCL component appears to be very similar to an Active X control, but it is much smaller, it links directly into your executable, and its architecture is much simpler, and much easier to understand than an ActiveX control's architecture. Unlike an ActiveX control, VCL components can only be used inside C++Builder and Delphi applications. There is a one a step menu driven process that will automatically convert a VCL component into an ActiveX control. After the conversion, the control is no longer linked directly into your program, is no longer so easy to understand, but can be used any place you can use ActiveX controls.

The ListStuff example is designed to hit the main points covered in this article. However, the STL is very flexible, and provides many different ways to accomplish the same ends. At least in theory, each way has its own virtues. To give you some sense of the flexibility of the STL, I have provided the MoreListStuff program that presents additional examples of how to use the STL. I will reference code from the MoreListStuff program throughout this article.

The remainder of this article briefly covers the STL examples shown in the ListStuff and MostListStuff programs. My goal will be to briefly show what each code fragment does, without ever attempting an inclusive or in depth discussion of the STL itself. However, if you have not worked with the STL before, you should gain a reasonable understanding of the subject by reading this article.

Working with Vectors
The STL vector class gives you an object oriented way to work with an array. As you will see, vectors are much more flexible than a standard C array. Furthermore, the vector class provides an excellent container for objects, while a standard C array often becomes irritable and hard to manage if you store objects in it.

Here is the code from the ListStuff program that manipulates the STL Vector class:

  vector<int> MyVector;
  int i;
  
  for (i = 0; i < 25; i++)
    XXXXXXXXXXXsert(MyVector.end(), i);

  ListBox1->Clear();
  
  for (i = 0; i < XXXXXXXXXXXze(); i++)
  {
    int j = MyVector[i];
    ListBox1->Items->Add(IntToStr(j));
  }
This code declares an instance of the vector class, then inserts 25 elements into the vector, adding each element at the end of the array. It then iterates through the array and displays each of its elements in a list box for the user's delectation and the connoisseur's inquiring perusal. When displaying the array, the program uses the size method of the vector class to find the number of elements that need to be enumerated.

Working with Iterators
As I stated earlier, the vector class is more flexible than the C array type. For instance, you can use the size method to retrieve the array's size, as shown in the previous section. The vector's flexibility is further exemplified by the following rewrite of the second for loop from the code fragment listed in the previous section of this text:

vector<int>::iterator Iterator;

for (Iterator = XXXXXXXXXXXgin(); Iterator != MyVector.end(); ++Iterator)
{
  ListBox1->Items->Add(*Iterator);
}
This example takes advantage of C++ class called an iterator. Iterators are designed to let you enumerate the members of a container such as a vector or list.

The code shown here first declares an iterator that is designed to work with a vector of type int. It then uses the begin and end methods of the iterator classes to mark the first and last elements of MyVector. The ++ operator can then be applied to the iterator to enumerate the values in the MyVector object.

Vectors Made Simple
Though it's fun to use, there is no doubt that vector syntax shown in the last few paragraphs can be overkill in some circumstances. Fortunately, there are ways to simplify this syntax if the user desires a more maintainable, less hectic implementation.

One of the goals of the vector class is to provide functionality more or less identical to the standard array type built into the language back from the Kerneghan and Ritchie days. For instance, this code from the MoreListStuff example program uses syntax which looks almost identical to the syntax you would use in a standard C program:

const int ListSize = 12;
int i;
vector<int> MyVector(ListSize);

for (i = 0; i < ListSize; ++i)
{
  MyVector[i] = i * i;
}

for (i = 0; i < int(XXXXXXXXXXXze()); ++i)
{
  ListBox1->Items->Add(MyVector[i]);
}
The key difference between this code and code which you might see in a C text written in 1980 is the actual declaration for MyVector. For comparison, here is the old declaration next to the new:

int MyVector[ListSize];
vector<int> MyVector(ListSize);
Most of the rest of the code is entirely agnostic, and would look the same in either C or C++. There is, of course, one other small difference, in that you can not ask a standard C array to report on its size, as we do here in the second for loop. To clean that up, I could have written:

for (i = 0; i < ListSize; i++)To my eye, either way of finding the end of the list is clean and easy to read, but using the size method makes you code at least potentially somewhat easier to maintain.

Vectors can be expanded or shrunk at run time. Use the size method to retrieve the current number of elements in a list. Use the capacity method to determine the current number of elements a list can contain, and use the reserve method to change the capacity of the list.

Working with Lists
Lists are another commonly used portion of the STL. The list template class is an encapsulation of the commonly used linked list algorithm. The differences between STL lists and a standard linked list that a programmer might implement are two fold:

XXXXe list type is ready made and thoroughly tested.
XXXX STL list will work with virtually any class you choose to place in it.
Unlike vectors, lists support efficient insertion of elements into any place in the list. A vector allows you to efficiently insert elements at the beginning or end of its array, but it does not handle insertion in the middle of the array very well because its memory is contiguous. In other words, if you insert an element in the middle of a vector, then the STL needs to move the remaining elements over one spot. A list, on the other hand, inserts elements at the beginning, end, and middle with more or less equal ease, needing only to link in the pointers that attach the new element.

Both lists and vectors can be expanded or shrunk at run time, so that issue is not a factor when deciding which type to use.

The following code from the ListStuff example shows how to take advantage of STL lists:

list<string, allocator<string> > MyList;
struct ffblk FindBlock;

list<string, allocator<string> >::iterator MyIterator;

int done = findfirst("*.*", &FindBlock, 0);

while (!done)
{
  XXXXXXXXXsert(XXXXXXXXXgin(), FindBlock.ff_name);
  done = findnext(&FindBlock);
}

ListBox1->Clear();

for (MyIterator = XXXXXXXXXgin(); MyIterator != MyList.end(); MyIterator++)
{
  string S = *MyIterator;
  ListBox1->Items->Add(S.c_str());
}

ofstream ofs("foo.dat");

for (MyIterator = XXXXXXXXXgin(); MyIterator != MyList.end(); MyIterator++)
{
  ofs << *MyIterator << endl;
}

ifstream ifs("Foo.dat");
string S;
ifs >> S;

ListBox1->Items->Add("From a stream: " + AnsiString(S.c_str()));
To get all this code to compile, you need to #include list, dir.h and fstream.h.

The code declares a list of strings and an iterator for use with the list:

list<string, allocator<string> > MyList;
list<string, allocator<string> >::iterator MyIterator;
Because the list template class is often used with the << and >> operators from the iostream class, it is best to include the odd, confusing, kluge-like spacing of the > symbol shown here when declaring the list. To not play along with this spacing syntax causes the compiler to emit a warning, which you are free to ignore.

My code then uses the standard findfirst and findnext C++ library functions to retrieve some file names that can be inserted into the list. Since I expect this program only to be run as an educational tool, I would imagine that most of the time the elements of the list will consist of the files in the ListStuff project. At any rate, the following syntax can be used to insert an element into the beginning of the list.

XXXXXXXXXsert(XXXXXXXXXgin(), FindBlock.ff_name);Or, if you choose, you can use one of the following methods:

XXXXXXXXXsert(MyList.end(), FindBlock.ff_name);
MyList.push_back(FindBlock.ff_name);
MyList.push_front(FindBlock.ff_name);
All of these methods do exactly what you expect them to do, so I won't bother explaining what they are about.

Here is code for iterating through the elements in a list:

for (MyIterator = XXXXXXXXXgin(); MyIterator != MyList.end(); MyIterator++)
{
  string S = *MyIterator;
  ListBox1->Items->Add(S.c_str());
}
This  code is nearly identical to the code used in the vector example, so I won't spend much time on it. Notice, however, that I have to pull the string out of the iterator and place it in a member of the C++ string template class. Then I use the c_str() method of the STL string class to extract the underlying char * value, which can be used by one of the constructors of the CBuilder AnsiString class, which is in turn used in the VCL list box class. All this tomfoolery will be unnecessary in CBuilder 4, because a constructor that takes an instance of the STL string class will be added to the AnsiString class.

*** Begin Note ***

Note: The AnsiString class is similar to the STL string class, but it specifically designed to enhance the unique features of the VCL.

***End Note***

A Few More Examples of Using Lists
I will not attempt to perform anything like a complete exegesis of the list template class in this article, but it takes only a moment to throw in a few more useful examples.

The following code will delete all the elements from the list:

XXXXXXXXXase(XXXXXXXXXgin(), MyList.end());Here is coding for finding an element in a list:
list<string>::iterator ElementIterator;
ElementIterator = find(XXXXXXXXXgin(), MyList.end(), "Main.cpp");
string Temp = *ElementIterator;
ListBox1->Items->Add(Temp.c_str());
The find function is not a method of an STL class. Instead, it is a stand alone routine designed to offer support to the STL and other parts of the C++ language. Both the ListStuff and MoreListStuff programs contain examples of using the find function on a standard C array.

STL Algorithms
Functions like find are sometimes referred to as algorithms. Here are list of some of the algorithms provided by the C++ language: find, search, count, sort, merge, rotate, reverse, random_shuffle, unique, remove, accumulate, generate, fill, transform, copy, for_each, equal, min and max.

I use some of these functions in various places throughout this paper. In particular, you find a number of examples of their use in the discussion of sets found near the end of this article.

Streaming a List
It is extremely easy to stream the elements of a list of strings:

ofstream ofs("foo.dat");

for (MyIterator = XXXXXXXXXgin(); MyIterator != MyList.end(); MyIterator++)
{
  ofs << *MyIterator << endl;
}
This code creates an "out" stream called ofs associated with the file foo.dat. It then iterates over all the elements in the list, and sends each of them to the stream, and thus into foo.dat itself.

The following code reads elements out of the file:

ifstream ifs("Foo.dat");
string S;

ifs >> S;

ListBox1->Items->Add("From a stream: " + AnsiString(S.c_str()));
This code creates an "in" stream called ifs. The code then declares an STL template string called S, and it copies a single string from foo.dat and into the warm embrace of the S template class.

In both of these examples you can see the usage of the aesthetically disarming << and >> operators. Note also the inelegant dance performed to convert an STL string into an AnsiString that can be used with the VCL list box class.

As stated earlier, you will be able to add instances of the STL string class directly to a list box in CBuilder 4:

ListBox1->Items->Add(MySTLString);The previous line of code is illegal in CBuilder 3, but will work in CBuilder 4.

Working with Deques
The queue and stack template classes are usually instances of a type of container called a deque. Deques are a lot like vectors, but they are especially designed to enhance the act of working with the first element in the array.

The stack Template Class
The stack template class has five methods called empty, size, pop, top and push. Here is an example from the ListStuff program of how to use most of them:


stack<int> MyStack;

ListBox1->Clear();
ListBox1->Items->Add("[s:9]ushing 5 on to the stack");
MyStack.push(5);
int i = XXXXXXXXXXp();
ListBox1->Items->Add("Checking top item on stack: " + IntToStr(i));
ListBox1->Items->Add("Adding four items to stack");

for (i = 0; i <= 4; i ++)
  MyStack.push(i);

MyStack.pop();
i = XXXXXXXXXXp();
ListBox1->Items->Add("[s:9]opping item from stack: " + IntToStr(i));
MyStack.pop();
i = XXXXXXXXXXp();
ListBox1->Items->Add("[s:9]opping item from stack: " + IntToStr(i));
This code will not compile unless you #include stack.

It is simple to declare an instance of a stack of int:

stack<int> MyStack;To add an element to this stack, use push:

MyStack.push(5);To retrieve, but not delete, an element from the stack, use top:

i = XXXXXXXXXXp();To delete, but not retrieve, an element from a stack, use pop:
MyStack.pop();To discover the size of a stack, use size, as shown here in this code from the MoreListStuff program:
stack<int> MyStack;
int i;

ListBox1->Clear();

for (i = 0; i <= 25; i++)
  MyStack.push(i * i);

int Size = XXXXXXXXXXze();

for (i = 0; i < Size; i++)
{
  int i = XXXXXXXXXXp();
  MyStack.pop();
  ListBox1->Items->Add(IntToStr(i));
}
Most programmers will probably prefer to use the empty method to achieve the same ends, when iterating through the elements of a stack:

while (!MyStack.empty())
{
  int i = XXXXXXXXXXp();
  MyStack.pop();
  ListBox1->Items->Add(IntToStr(i));
}
The while loop shown here should be compared with the for loop in the last few lines of code from the previous example. Both show legal ways to iterate through the elements of a stack.

Working with Queues
Queues are a lot like stacks, but they support the idea of retrieving an element from either the front or the back of the array of elements in the queue:

queue<int> MyQueue;

MyQueue.push(5);
MyQueue.push(6);
MyQueue.push(7);
ListBox1->Clear();
int i = XXXXXXXXXXont();
ListBox1->Items->Add("Front: " + IntToStr(i));
i = XXXXXXXXXXck();
ListBox1->Items->Add("Back: " + IntToStr(i));
In this case I push three elements on the queue, and the retrieve the first and last elements by using the front and back methods. After the code executes, the numbers 5 and 7 are placed, in that order, in the list box.

Other than including the front and back methods, queues add nothing to the behavior of stacks. In other words, the code I showed for working with stacks will also work with queues, but the code I show for working with queues won't work with stacks.

Working with Sets
Though similar to stacks, queues, lists and vectors, a set plays a somewhat different role in most programs. In particular, sets provide methods for easily checking for inclusion, and for comparing two sets of elements. There are tools for finding the union of two sets, for finding the difference between two sets, and for finding the intersection between two sets. As you will see, sets are a bit more difficult to understand than the other relatively straightforward types discussed so far in this paper.

Here is an example of using the Set template class:

  set<int> MySet;
  set<int>::iterator MyIterator;
  int i;

  for (i = 1; i <= 10; ++i)
    XXXXXXXXsert(i);

  MyIterator = XXXXXXXXgin();
  i = *MyIterator;
  ListBox1->Clear();
  ListBox1->Items->Add("First element in set: " + IntToStr(i));
  ListBox1->Items->Add("");
  ListBox1->Items->Add("The whole set: ");

  for (XXXXXXXXgin(); MyIterator != MySet.end(); MyIterator++)
    ListBox1->Items->Add(IntToStr(*MyIterator));
This code declares a set of type int, and an iterator to enumerate its elements. It uses the insert method of the set template class to add elements to the set, and then uses the iterator to extract elements from the set.

I play around with the iterator a bit, just for the sake of variety. For the sake of clarity, I provide the following code fragment to show you how iterators would be used with sets in a somewhat simpler context:

for (MyIterator = XXXXXXXXgin(); MyIterator != MySet.end(); MyIterator++)
  ListBox1->Items->Add(IntToStr(*MyIterator));
Here is yet another way to iterate over the elements of a set:

set<int> MySet;
set<int>::iterator MyIteratorBegin, MyIteratorEnd;
int i;

for (i = 1; i <= 10; ++i)
  XXXXXXXXsert(i);

MyIteratorBegin = XXXXXXXXgin();
MyIteratorEnd = MySet.end();

while (MyIteratorBegin != MyIteratorEnd)
{
  ListBox1->Items->Add(IntToStr(*MyIteratorBegin));
  MyIteratorBegin++;
}
In this code two iterators are provided, one for marking the beginning of a set, and one for marking the end. The code iterates through the first of the two iterators until it returns the same value as the iterator marking the end of the set.

Using the count Algorithm with Sets
You can use the count method of the set template class to find out if an element is included in a set:

set<int> MySet;
int i;

for (i = 1; i <= 10; ++i)
  XXXXXXXXsert(i);

AnsiString Item;

if (InputQuery("Enter a number to see if it is in the set", "Number", Item))
{
  if (XXXXXXXXunt(StrToInt(Item)))
    ListBox1->Items->Add("Found element");
  else
    ListBox1->Items->Add("Element not found");
}
This code from the MoreListStuff program queries the user to enter a number. If the number is between one and ten, then the program prints the string "Found element" in the list box. Other wise, it reports that the element was not found. The count method returns 1 if the element is found and 0 if it is not.

The find method returns an iterator containing the element you queried for if it is a member of the set:

if (InputQuery("Enter a number to see if it is in the set", "Number", Item))
{
  set<int>::iterator Items = XXXXXXXXnd(StrToInt(Item));
  if (Items != MySet.end())
    ListBox1->Items->Add("Found element");
  else
    ListBox1->Items->Add("Element not found");
}
If the iterator is not equal to the value return by the end method of the set, then the item you went fishing after was found.

Working with Set Inserters
As shown in the MoreListStuff program, you can use the inserter class to iterate over a list of strings and insert each one into a set:

static string MyStrings[5] = {"A Kiss:", "Keep", "it", "simple", "stupid"};
set <string> WordsOfWisdom;
set <string>::iterator MyIterator;

copy (MyStrings, MyStrings+5, inserter(WordsOfWisdom, XXXXXXXXXXXXXXXXgin()));

for (MyIterator = XXXXXXXXXXXXXXXXgin(); MyIterator != WordsOfWisdom.end(); MyIterator++)
{
  string S = *MyIterator;
  ListBox1->Items->Add(S.c_str());
}
Here the copy function is taken through its paces. The first two parameters of the copy function mark the beginning and end of the range of elements to be copied. I pass in a STL string class array, but you could pass in an iterator instead. The last parameter is the inserter, which in this case is used to singly insert each element into the beginning of the set. In other words, it repeatedly calls the insert method for you, rather forcing you to perform that chore your self in some kind of loop.

Working with Sets, Unions, Intersections and Differences
The code in this section makes sets of two verses from the William Blake poem The Divine Image. It then uses the capabilities of the set class to compare and contrast the words found in each verse. Here are the verses:

To Mercy, Pity, Peace, and Love,
All pray in their distress,
And to these virtues of delight
Return their thankfulness.

For Mercy, Pity, Peace, and Love,
Is God our Father dear;
And Mercy, Pity, Peace, and Love,
Is man, his child and care.
Here is the code:

static string Verse1[20] = {"To", "Mercy", "[s:9]ity", "[s:9]eace", "and", "Love", "All", "pray", "in", "their", "distress", "and", "to", "these", "virtues", "of", "delight", "Return", "their", "thankfulness"}; static string Verse2[23] = {"For", "Mercy", "[s:9]ity", "[s:9]eace", "and", "Love", "Is", "God", "our", "Father", "dear", "And", "Mercy", "[s:9]ity", "[s:9]eace", "and", "Love", "Is", "man", "his", "child", "and", "care"}; set<string> VerseOne(Verse1, Verse1+20); set<string> VerseTwo(Verse2, Verse2+23); set<string> MySet; set_difference(XXXXXXXXXXXgin(), VerseOne.end(), XXXXXXXXXXXgin(), VerseTwo.end(), inserter(MySet, XXXXXXXXgin())); set<string>::iterator MySetIterator; ListBox1->Clear(); ListBox1->Items->Add("--- Difference ---"); for (MySetIterator = XXXXXXXXgin(); MySetIterator != MySet.end(); MySetIterator++) { string S = *MySetIterator; ListBox1->Items->Add(S.c_str()); }
First I declare an array of strings containing the two versus, then I declare two sets and insert the verses into them:

set<string> VerseOne(Verse1, Verse1+20);
set<string> VerseTwo(Verse2, Verse2+23);
I get the difference between the two sets with the following code:

set_difference(XXXXXXXXXXXgin(), VerseOne.end(),
  XXXXXXXXXXXgin(), VerseTwo.end(),
  inserter(MySet, XXXXXXXXgin()));
The set_difference method requests iterators marking the beginning and end of the first set, and iterators marking the beginning and end of the second set. In return for your efforts, it provides a third set containing the difference between the two sets. In other words, the third set contains words that appear in each verse, but not in both verses. Notice that I use an inserter to insert the result into the return set.

Here is code for finding the union between two sets:

set_union(XXXXXXXXXXXgin(), VerseOne.end(),
  XXXXXXXXXXXgin(), VerseTwo.end(),
  inserter(MySet, XXXXXXXXgin()));
Once you understand the pattern involved, it is easy to find the intersection between two sets:

set_intersection(XXXXXXXXXXXgin(), VerseOne.end(),
  XXXXXXXXXXXgin(), VerseTwo.end(),
  inserter(MySet, XXXXXXXXgin()));
Needless to see, this function returns the set "Love", "Mercy", "[s:9]eace", "[s:9]ity" and "and".

Summary
In this brief paper you have seen several examples of using the VCL and the STL in the same application. Though the paper does provide an overview of certain of the more important features of the STL, its primary purpose is to make explicitly clear the fact that C++Builder is a real C++ compiler that supports all the key features of the C++ language.

While writing the paper, you learned that vectors are array-like classes that work well when inserting elements at the beginning or end of the array. Lists are handy if you need to insert elements in the middle of the list of elements. Queues and stacks are optimized for insertion and removal at the top of a list of items.

C++Builder uses the same compiler that is found in Borland C++ 5.0. This is an award winning compiler that has been a standard in the industry for many years. Unlike any other compilers on the market, it can be used to compile OWL, MFC, and VCL code. Furthermore, C++Builder 4.0 will track closely the ANSI/ISO Final Draft Standard for the C++ language.

XXXXXXXXXXXXXXXXXXXXXXXXXX/article/10284
来自:计算机科学 / 软件综合
2
已屏蔽 原因:{{ notice.reason }}已屏蔽
{{notice.noticeContent}}
~~空空如也
joyeep
14年3个月前 IP:未同步
210508
STL 是C++标准库
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论

想参与大家的讨论?现在就 登录 或者 注册

所属专业
上级专业
同级专业
我说要有光
进士 学者 机友 笔友
文章
317
回复
5531
学术分
15
2008/03/06注册,1天0时前活动

Inspiration, Innovation, Discovery

主体类型:个人
所属领域:无
认证方式:手机号
IP归属地:未同步
文件下载
加载中...
{{errorInfo}}
{{downloadWarning}}
你在 {{downloadTime}} 下载过当前文件。
文件名称:{{resource.defaultFile.name}}
下载次数:{{resource.hits}}
上传用户:{{uploader.username}}
所需积分:{{costScores}},{{holdScores}}下载当前附件免费{{description}}
积分不足,去充值
文件已丢失

当前账号的附件下载数量限制如下:
时段 个数
{{f.startingTime}}点 - {{f.endTime}}点 {{f.fileCount}}
视频暂不能访问,请登录试试
仅供内部学术交流或培训使用,请先保存到本地。本内容不代表科创观点,未经原作者同意,请勿转载。
音频暂不能访问,请登录试试
支持的图片格式:jpg, jpeg, png
插入公式
评论控制
加载中...
文号:{{pid}}
投诉或举报
加载中...
{{tip}}
请选择违规类型:
{{reason.type}}

空空如也

加载中...
详情
详情
推送到专栏从专栏移除
设为匿名取消匿名
查看作者
回复
只看作者
加入收藏取消收藏
收藏
取消收藏
折叠回复
置顶取消置顶
评学术分
鼓励
设为精选取消精选
管理提醒
编辑
通过审核
评论控制
退修或删除
历史版本
违规记录
投诉或举报
加入黑名单移除黑名单
查看IP
{{format('YYYY/MM/DD HH:mm:ss', toc)}}