9.1. Defining a Sequential Container9.1. 顺序容器的定义We already know a fair bit about how to use the sequential containers based on what we covered in Section 3.3 (p. 90). To define a container object, we must include its associated header file, which is one of 在第 3.3 节中,我们已经了解了一些使用顺序容器类型的知识。为了定义一个容器类型的对象,必须先包含相关的头文件,即下列头文件之一: #include <vector> #include <list> #include <deque> Each of the containers is a class template (Section 3.3, p. 90). To define a particular kind of container, we name the container followed by angle brackets that enclose the type of the elements the container will hold: 所有的容器都是类模板(第 3.3 节)。要定义某种特殊的容器,必须在容器名后加一对尖括号,尖括号里面提供容器中存放的元素的类型: vector<string> svec; // empty vector that can hold strings list<int> ilist; // empty list that can hold ints deque<Sales_item> items; // empty deque that holds Sales_items Each container defines a default constructor that creates an empty container of the speicfied type. Recall that a default constructor takes no arguments. 所有容器类型都定义了默认构造函数,用于创建指定类型的空容器对象。默认构造函数不带参数。
9.1.1. Initializing Container Elements9.1.1. 容器元素的初始化In addition to defining a default constructor, each container type also supports constructors that allow us to specify initial element values. 除了默认构造函数,容器类型还提供其他的构造函数,使程序员可以指定元素初值,见表 9.2。
Intializing a Container as a Copy of Another Container将一个容器初始化为另一个容器的副本When we initialize a sequential container using any constructor other than the default constructor, we must indicate how many elements the container will have. We must also supply initial values for those elements. One way to specify both the size and element values is to initialize a new container as a copy of an existing container of the same type: 当不使用默认构造函数,而是用其他构造函数初始化顺序容器时,必须指出该容器有多少个元素,并提供这些元素的初值。同时指定元素个数和初值的一个方法是将新创建的容器初始化为一个同类型的已存在容器的副本: vector<int> ivec; vector<int> ivec2(ivec); // ok: ivec is vector<int> list<int> ilist(ivec); // error: ivec is not list<int> vector<double> dvec(ivec); // error: ivec holds int not double
Initializing as a Copy of a Range of Elements初始化为一段元素的副本Although we cannot copy the elements from one kind of container to another directly, we can do so indirectly by passing a pair of iterators (Section 3.4, p. 95). When we use iterators, there is no requirement that the container types be identical. The element types in the containers can differ as long as they are compatible. It must be possible to convert the element we copy into the type held by the container we are constructing. 尽管不能直接将一种容器内的元素复制给另一种容器,但系统允许通过传递一对迭代器(第 3.4 节)间接实现该实现该功能。使用迭代器时,不要求容器类型相同。容器内的元素类型也可以不相同,只要它们相互兼容,能够将要复制的元素转换为所构建的新容器的元素类型,即可实现复制。 The iterators denote a range of elements that we want to copy. These elements are used to initialize the elements of the new container. The iterators mark the first and one past the last element to be copied. We can use this form of initialization to copy a container that we could not copy directly. More importantly, we can use it to copy only a subsequence of the other container: 迭代器标记了要复制的元素范围,这些元素用于初始化新容器的元素。迭代器标记出要复制的第一个元素和最后一个元素。采用这种初始化形式可复制不能直接复制的容器。更重要的是,可以实现复制其他容器的一个子序列: // initialize slist with copy of each element of svec list<string> slist(svec.begin(), svec.end()); // find midpoint in the vector vector<string>::iterator mid = svec.begin() + svec.size()/2; // initialize front with first half of svec: The elements up to but not including *mid deque<string> front(svec.begin(), mid); // initialize back with second half of svec: The elements *mid through end of svec deque<string> back(mid, svec.end()); Recall that pointers are iterators, so it should not be surprising that we can initialize a container from a pair of pointers into a built-in array: 回顾一下指针,我们知道指针就是迭代器,因此允许通过使用内置数组中的一对指针初始化容器也就不奇怪了: char *words[] = {"stately", "plump", "buck", "mulligan"}; // calculate how many elements in words size_t words_size = sizeof(words)/sizeof(char *); // use entire array to initialize words2 list<string> words2(words, words + words_size); Here we use sizeof (Section 5.8, p. 167) to calculate the size of the array. We add that size to a pointer to the first element to get a pointer to a location one past the end of the array. The initializers for words2 are a pointer to the first element in words and a second pointer one past the last element in that array. The second pointer serves as a stopping condition; the location it addresses is not included in the elements to be copied. 这里,使用 sizeof(5.8 节)计算数组的长度。将数组长度加到指向第一个元素的指针上就可以得到指向超出数组末端的下一位置的指针。通过指向第一个元素的指针 words 和指向数组中最后一个元素的下一位置的指针,实现了 words2 的初始化。其中第二个指针提供停止复制的条件,其所指向的位置上存放的元素并没有复制。 Allocating and Initializing a Specified Number of Elements分配和初始化指定数目的元素When creating a sequential container, we may specify an explicit size and an (optional) initializer to use for the elements. The size can be either a constant or non-constant expression. The element initializer must be a valid value that can be used to initialize an object of the element type: 创建顺序容器时,可显式指定容器大小和一个(可选的)元素初始化式。容器大小可以是常量或非常量表达式,元素初始化则必须是可用于初始化其元素类型的对象的值: const list<int>::size_type list_size = 64; list<string> slist(list_size, "eh?"); // 64 strings, each is eh? This code initializes slist to have 64 elements, each with the value eh?. 这段代码表示 slist 含有 64 个元素,每个元素都被初始化为“eh?”字符串。 As an alternative to specifying the number of elements and an element initializer, we can also specify only the size: 创建容器时,除了指定元素个数,还可选择是否提供元素初始化式。我们也可以只指定容器大小: list<int> ilist(list_size); // 64 elements, each initialized to 0 // svec has as many elements as the return value from get_word_count extern unsigned get_word_count(const string &file_name); vector<string> svec(get_word_count("Chimera")); When we do not supply an element initializer, the library generates a value-initialized (Section 3.3.1, p. 92) one for us. To use this form of initialization, the element type must either be a built-in or compound type or be a class type that has a default constructor. If the element type does not have a default constructor, then an explicit element initializer must be specified. 不提供元素初始化式时,标准库将为该容器实现值初始化(3.3.1&nbps;节)。采用这种类型的初始化,元素类型必须是内置或复合类型,或者是提供了默认构造函数的类类型。如果元素类型没有默认构造函数,则必须显式指定其元素初始化式。
9.1.2. Constraints on Types that a Container Can Hold9.1.2. 容器内元素的类型约束While most types can be used as the element type of a container, there are two constraints that element types must meet: C++ 语言中,大多数类型都可用作容器的元素类型。容器元素类型必须满足以下两个约束:
There are additional constraints on the types used as the key in an associative container, which we'll cover in Chapter 10. 此外,关联容器的键类型还需满足其他的约束,我们将在第十章介绍相关内容。 Most types meet these minimal element type requirements. All of the built-in or compound types, with the exception of references, can be used as the element type. References do not support assignment in its ordinary meaning, so we cannot have containers of references. 大多数类型满足上述最低限度的元素类型要求。除了引用类型外,所有内置或复合类型都可用做元素类型。引用不支持一般意义的赋值运算,因此没有元素是引用类型的容器。 With the exception of the IO library types (and the auto_ptr type, which we cover in Section 17.1.9 (p. 702)), all the library types are valid container element types. In particular, containers themselves satisfy these requirements. We can define containers with elements that are themselves containers. Our Sales_item type also satisifes these requirements. 除输入输出(IO)标准库类型(以及第 17.1.9 节介绍的 auto_ptr 类型)之外,所有其他标准库类型都是有效的容器元素类型。特别地,容器本身也满足上述要求,因此,可以定义元素本身就是容器类型的容器。Sales_item 类型也满足上述要求。 The IO library types do not support copy or assignment. Therefore, we cannot have a container that holds objects of the IO types. IO 库类型不支持复制或赋值。因此,不能创建存放 IO 类型对象的容器。 Container Operations May Impose Additional Requirements容器操作的特殊要求The requirement to support copy and assignment is the minimal requirement on element types. In addition, some container operations impose additional requirements on the element type. If the element type doesn't support the additional requirement, then we cannot perform that operation: We can define a container of that type but may not use that particular operation. 支持复制和赋值功能是容器元素类型的最低要求。此外,一些容器操作对元素类型还有特殊要求。如果元素类型不支持这些特殊要求,则相关的容器操作就不能执行:我们可以定义该类型的容器,但不能使用某些特定的操作。 One example of an operation that imposes a type constraint is the constructors that take a single initializer that specifies the size of the container. If our container holds objects of a class type, then we can use this constructor only if the element type has a default constructor. Most types do have a default constructor, although there are some classes that do not. As an example, assume that Foo is a class that does not define a default constructor but that does have a constructor that takes an int argument. Now, consider the following declarations: 其中一种需外加类型要求的容器操作是指定容器大小并提供单个初始化式的构造函数。如果容器存储类类型的对象,那么只有当其元素类型提供默认构造函数时,容器才能使用这种构造函数。尽管有一些类没有提供默认构造函数,但大多数类类型都会有。例如,假设类 Foo 没有默认构造函数,但提供了需要一个 int 型形参的构造函数。现在,考虑下面的声明: vector<Foo> empty; // ok: no need for element default constructor vector<Foo> bad(10); // error: no default constructor for Foo vector<Foo> ok(10, 1); // ok: each element initialized to 1 We can define an empty container to hold Foo objects, but we can define one of a given size only if we also specify an initializer for each element. 我们定义一个存放 Foo 类型对象的空容器,但是,只有在同时指定每个元素的初始化式时,才能使用给定容器大小的构造函数来创建同类型的容器对象。 As we describe the container operations, we'll note the constraints, if any, that each container operation places on the element type. 在描述容器操作时,我们应该留意(如果有的话)每个操作对元素类型的约束。 Containers of Containers容器的容器Because the containers meet the constraints on element types, we can define a container whose element type is itself a container type. For example, we might define lines as a vector whose elements are a vector of strings: 因为容器受容器元素类型的约束,所以可定义元素是容器类型的容器。例如,可以定义 vector 类型的容器 lines,其元素为 string 类型的 vector 对象: // note spacing: use ">>" not ">>" when specifying a container element type vector< vector<string> > lines; // vector of vectors Note the spacing used when specifying a container element type as a container: 注意,在指定容器元素为容器类型时,必须如下使用空格: vector< vector<string> > lines; // ok: space required between close > vector< vector<string>> lines; // error: >> treated as shift operator
![]() |