c++编程中vector容器当中插入map容器为什么不行

c++编程中vector容器当中插入map容器为什么不行,第1张

容器用来存储数据的,数据可以是用户自定义类型(对象),也可以是预定义类型,c++中的容器主要使用如vector,list (顺序容器) 这些都是已经封装好了的,包含头文件"vector","list",通过迭代器iterator访问容器中的数据,map,set(关联容器),关联容器map键值对形式出现key-value,key唯一,mutimap多映射可以不唯一;set是一个单一值的集合,如1,2,3,4

顺序容器:vector,list 分别举例 对比

vector容器的特点:在内存中是一片连续的存储区域,初始化的时候,可以指定容量,比如如果定义容量50 的容器存储 60个string对象,由于初始容量不足60,容器将会重新定义一个容量是原来的2倍新容器,然后拷贝原容器的对象到新容器. 读取速度快,插入删除效率低.如果仅仅在容器头或尾部 进行增删改,推荐使用deque,专门提供了对首尾的 *** 作.

list容器特点:相当数据结构的链表,不是一个连续的存储区域,插入,删除很方便,但是查询速度慢

vector<string>vec 就是定义了一个vector容器,可以通过

vec.push_back(), push_font(),insert(position,value) 想vector中添加一个指定值

list<int>ilist<初始大小,默认赋值>list<int>ilist(20 -1) 初始20个值为-1的list

然后 *** 作可以参考这些这些类封转的方法。

关联容器:set map mutimap mutiset

key-->value形式

1--1

2--2

3--3

set 形式 1234,键值唯一

具体容器的 *** 作方法,可以调用其成员函数.

代码如下:

std::vector<int>src

std::vector<int>dest

dest.insert(dest.end(),src.begin(),src.end())

插到其他位置同理,只需要改变第一个迭代器参数。

扩展资料:

编译&执行C++程序方法:

1、打开vs2010,选择"visualc++开发设置",然后点击"启动VisualStudio"。

2、"VisualStudio"选择默认环境设置。

3、进入"VisualStudio"后点击新建项目。

4、在d出窗口选择VisualC++标签下的空项目,输入名称以及保存位置。

5、在左侧的"解决方案资源管理器"中,选择"源文件"右击,然后选择"添加"->"新建项"。

6、在d出窗口中,选择"C++文件(.cpp)",输入文件名称,单击"添加"。

7、现在输入具体的代码,例如输入简单的HelloWorld程序。

8、依次单击"调试"->"开始执行(不调试)"或按Ctrl+F5开始运行。

1. CArray<>VS ::std::vector<>?

CArray<>和 ::std::vector<>一样,都是模板类,用于管理任意类型的对象的动态数组。都在解构时释放所管理的动态内存。因此都可以用于代替手工动态数组管理。

但是,CArray<>是在 C++ 标准化之前很多年(VC++2.0时代)设计的,当时对 C++程序设计,面向对象程序设计,模板程序设计等技术认识严重不足,尤其是当时对面向对象技术的错误信仰与宣传,造成 CArray<>的设计有重大错误。

在 C++ 语言标准化以后(1998),以及 VC++ 6.0 出世以后,提供了标准的::std::vector<>模板,基本上在任何方面都要优于 CArray<>。Microsoft 由于要支持老的程序,因此一直保留了 CArray<>,但显然并没有打算按照新的思想去发展它(至少应该提供operator=(CArray const&)吧)。

概括起来,CArray<>与 ::std::vector<>有以下不同:

1) CArray<>是 MFC 中的,::std::vector<>存在于任何标准的 C++ 实现中。因此,你用熟了 CArray<>也只能在 MFC 中用,若用熟了 ::std::vector<>,你可以在任何平台的任何 C++ 编译器下使用。使用标准的部件也有利于别人理解你的程序。 . CArray<>继承了 CObject,仅仅为了实现 serialization,这是不恰当的, 违反了 "You don't pay for what you don't use." 的 C++ 设计原则。::std::vector<>没有继承任何东西,只是实现了管理一个动态数组该做的事。

2) CArray<>不是一个恰当的值类型,例如下列 *** 作都是不合法的:

CArray<int,int>a

CArray<int,int>b(a) // error, must use Copy().

b = a// error, must use Copy().

b == a  // error, you must write your own.

b <a// error, you must write your own.

与 CArray<>相反,::std::vector<>是一个认真设计的值类型,天生是可以拷贝构造和可赋值的。如果 T 是可比较的,那么 ::std::vector<T>将自动地是可以比较的。

此外,由于涉及到四个特殊成员函数;

T()// 缺省构造函数(default constructor)

~T()// 解构函数(destructor)

T( T const&)// 拷贝构造函数

T&operator=( T const&)// 拷贝赋值函数

的自动生成,如果使用 CArray() 作为 T 的成员变量,那么上述的四个特殊函数中的后两个将无法自动生成,需要手工写:

struct T

{

  T() {}

  T( T const&t )

  {

  a_.Copy( t.a_ )

  i_ = t.i_

  d_ = t.d_

  s_ = t.s_

  }

  T&operator = ( T const&t )

  {

  if( this != &t )

  {

  a_.Copy( t.a_ )

  i_ = t.i_

  d_ = t.d_

  s_ = t.s_

  }

  return *this

  }

private:

  CArray<int,int>a_

  int i_

  double d_

  ::std::string s_

}

如果使用 ::std::vector<>:

struct T

{

private:

  ::std::vector<int>a_

  int i_

  double d_

  ::std::string s_

}

上面列出的三个特殊成员函数都不需要写。好处是明显的:当你增减 T 的成员变量时,你不必到T(T const&) 和 operator=() 中去相应地增减。

3) 没有现成的算法可以对 CArray<>进行 *** 作,而标准 C++ 里的标准算法大多都可以直接在

::std::vector<>上运行。例如:

static int const init_vals[] = { 3, 1, 4, 1, 6, 9 }

vector<int>a( init_vals, init_vals + 6 )

*find( a.begin(), a.end(), 6 ) = 5// 把6改成5

sort( a.begin(), a.end() )// 排序。

可以说,CArray<>的主要设计错误是把一个本来应该是一个简单的“值”类型的东西设计成一个难用的“对象”类型了。所有的“值”的好特性都丧失了,但那些从CArray<>继承的派生类呢?

CByteArray等的问题与 CArray<>的问题一样,甚至更多(例如,CPtrArray,永远不要用)。

同样,其他的 MFC container 模板,象 CMap<>, CList<>等,都有类似问题,都应该用

::std::map<>,::std::list<>等设计更好的东西代替。

2. ::std::vector<>在哪里?

::std::vector<>在头文件 <vector>中定义:

(注意,标准的 C++ 头文件都没有 .h 后缀,有 .h 的文件是与 C 兼容的,或支持老的不标准的东西,象 <iostream.h>。)

namespace std

{

template<typename T, typename A = allocator<T>>

struct vector

{

// 具体内容稍后讨论

}

template<typename T, typename A>

bool operator == ( vector<T,A>const&a, vector<T,A>const&b )

template<typename T, typename A>

bool operator != ( vector<T,A>const&a, vector<T,A>const&b )

template<typename T, typename A>

bool operator <( vector<T,A>const&a, vector<T,A>const&b )

template<typename T, typename A>

bool operator >= ( vector<T,A>const&a, vector<T,A>const&b )

template<typename T, typename A>

bool operator >( vector<T,A>const&a, vector<T,A>const&b )

template<typename T, typename A>

bool operator >= ( vector<T,A>const&a, vector<T,A>const&b )

}

vector<>定义在 namespace std 中,使用时为了减少击键次数,通常使用一个类型定义缩短类型名称:

#include <vector>

typedef ::std::vector<int>IntVector

IntVector a

IntVector b( a )

IntVector c

c = b

assert( a == c )

请注意 <vector>中定义了六个 vector<T,A>的比较函数。这些函数只在真的用到时才会被实例化,才会要求 T 也提供 operator==() 和 operator<()。

另外,A = alloctor<T>:用于提供一个用户定义的存储管理类。由于这个参数很少用到,而且在 VC++6 的实现中有问题,不能用,因此以下的讨论忽略这一部分的内容。

3. ::std::vector<>中的类型定义

vector<>中定义了一些类型,下面只列出常用的:

typedef T value_type

typedef T0 iterator

typedef T1 const_iterator

typedef T2 reverse_iterator

typedef T3 const_reverse_iterator

value_type 就是 vector<T>的元素类型,也就是 T。当写通用的算法处理任意类型的 vector<>或其他容器类型时是很有用的。

iterator/const_iterator 是两个 vector<>的实现定义的未知类型,用于访问vector<>中的元素,类似于 T*/T const* 指针,他们的区别是一个指向的元素可被修改,另一个只可以读:

typedef ::std::vector<int>IntVector

IntVector::iterator iter

IntVector::const_iterator c_iter

// ...

++iteriter++// ok: increment, post-increment.

--iteriter--// ok: decrement, post-decrement.

++c_iterc_iter++// ok: increment, post-increment.

--c_iterc_iter--// ok: decrement, post-decrement.

*iter = 123// ok.

int k = *iter// ok.

k = *--c_iter// ok.

*c_iter = k// error.

c_iter = iter// ok: iterator is convertible to const_iterator.

iter = c_iter// error: can't convert const_iterator to iterator.

在使用上 iterator/const_iterator 和 T*/T const* 基本相同,事实上有些vector<>的实现里就是用 T*/T const* 实现 iterator/const_iterator 的,但又不可以把 iterator/const_iterator 当作真正的 T*/T const*:

T* p = iter// may fail to compile.

T const* q = c_iter// may fail to compile.

reverse_iterator/const_reverse_iterator 与 iterator/const_iterator 类似,但以相反的次序(从尾至头)访问 vector 中的元素。

各种各样的 iterator 在 STL 中有特别重要的意义,但这里我们不做具体介绍。只要理解通过 iterator 可以访问 vector 中的元素,大概相当于一个指示位置的指针就行了。

4. ::std::vector<>的构造

vector<>提供了以下构造函数:(忽略 allocator 参数)

vector()

vector( size_t n, T const t=T() )

vector( vector const &)

vector( const_iterator first, const_iterator last )

1) vector()

构造一个空的 vector,不包含任何元素。

IntVector v1// 空的整数向量。

2) vector( size_t n, T const t=T() )

构造一个 n 个相同元素 t 组成的 vector。如果不给出 t,那么将用 T() 做缺省值:

IntVector v2( 100, 1234 )// 100 个 1234.

IntVector v3( 100 )// 100 个 0。

3) vector( vector const&other )

复制构造函数,复制 other 中的内容:

IntVector v4( v2 )// 100 个 1234。

4) vector( const_iterator first, const_iterator last )

事实上,这个构造函数应该为

template<typename Iter>

vector( Iter first, Iter last )

即拷贝任意的序列 [first,last) 到 vector 中。由于 VC++6sp0 编译程序的限制, Iter 被换为 const_iterator 了。不过,碰巧 const_iterator就是 T const*,所以可以如下使用:

int a[] = { 1, 2, 3, 4, 5 }

IntVector v5( a, a + 5 )// {1,2,3,4,5}

IntVector v6( v5.begin() + 2, v5.end() )// {3,4,5}

5. 访问 vector<>中的元素

以下成员函数/运算符用于访问 vector 中的一个元素:

T&at( size_t n )

T const&at( size_t n ) const

T&operator [] ( size_t n )

T const&operator [] ( size_t n ) const

T&front()

T const&front() const

T&back()

T const&back() const

请注意,由于 vector 是一个“值”语义的对象,所有的 *** 作函数都必须严格保证 const 的正确性。所以,所有的元素访问方法都有 const 和非 const两个版本。

at(n) 和 operator [] (n) 都返回下标为 n 的元素的引用,他们的区别是,at() 进行下标越界检查,若发现越界,抛出 range_error 异常,operator[]不进行下标检查。

front() 返回下标为 0 的元素的引用,back() 返回最后一个元素的引用。

int a[] = { 4, 1, 4, 1, 5, 8 }

IntVector v( a, a + 6 )

// 使用 front(), back():

v.front() = 3

v.back() = 9

// 使用 operator [] ():

for( size_t i = 0i <v.size()++i )

::std::cout <<v[i] <<'\n'

6. ::std::vector<>的存储管理

以下成员函数用于存储管理:

void reserve( size_t n )

size_t capacity() const

void resize( size_t n, T t=T() )

void clear()

size_t size() const

bool empty() const { return size() == 0}

size_t max_size() const

另外,push_back(), insert() 等也涉及到存储管理,后面另行介绍。

1) max_size()

返回 vector<T>理论上可以装的最多 T 的个数。这只是一个理论上的数字,大概是 4GB/sizeof(T),没有多大实用价值。在程序中不要用。

2) size()

返回 vector<T>中实际装的 T 的个数。相当于 CArray<>::GetSize()。

3) empty()

如果 vector<T>中没有任何 T 对象,返回 true。也就是返回 size() == 0。

4) clear()

清除 vector<T>中的所有 T 对象。执行后 empty() 返回 true。大致相当于 resize(0),但不要求 T 可被缺省构造。相当于 CArray<>::RemoveAll()。

5) resize( size_t n, T t = T() )

将 vector 中的元素个数设置为 n,n 可以大于 size() 也可以小于 size。如果 n 小于 size(),那么 vector 中下标为 n..size()-1 的元素都将被解构。如果 n >size(),那么将在 vector 的后面新增加

n - size() 个相同的元素 t。在增大 vector 时,可能发生存储再次分配。总之,调用resize( n, t ) 后,(size() == n) 成立。

请注意,如果调用 resize( n ) 不带参数 t ,那么 T 必须可以缺省构造。

6) reserve( size_t n )

事先分配至少可以保存 n 个 T 对象的空间。调用后 (capacity() >= n)成立。

7) capacity()

返回已经分配的存储空间够容纳的 T 类型对象的个数。后续的增加元素 *** 作(如 push_back(), insert())如果增加元素后 vector 中的总元素个数不超过 capacity(),那么 vector 的实现保证不重新分配存储空间。

vector 管理的动态存储空间是连续的。执行 *** 作

IntVector v(7, 1)// seven ones.

v.reserve( 12 )

后,v 的状态可以用下图表示:

/--size()---\

|1|1|1|1|1|1|1|-|-|-|-|-|

\--capacity()---------/

其中,1 是已经构造的 int 类型的对象,- 是可以构造一个 int 类型的对象,但还没有构造的原始空间。再执行

v.push_back( 2 )

v.push_back( 3 )

后,v 的状态可用下图表示:

/----size()-----\

|1|1|1|1|1|1|1|2|3|-|-|-|

\----capacity()-------/

执行 resize( 11, 4 )后:

/----size()---------\

|1|1|1|1|1|1|1|2|3|4|4|-|

\----capacity()-------/

capacity() >= size() 总是成立的。对于下标为 [size()..capacity()-1]的未构造对象的存储空间,是不可以访问的:

v[11] = 5// undefined behavior - anything can happen.7. 添加元素到 vector 中

下列 *** 作添加元素到 vector 中,并可能引起存储分配:

void push_back( T const&t )

void insert( iterator pos, T const&t=T() )

void insert( iterator pos, size_t n, T const&t )

template<typename Iter>

void insert( iterator pos, Iter first, Iter last )

push_back() 是把一个元素添加到 vector 的末尾。insert() 是把一个 t,或 n 个 t,或从 first 开始到 last 结束的一个序列插入到 pos 指示的位置之前。

当插入元素后 size() 将会大于 capacity() 时,将引起自动存储分配。vector 将会分配一个比需要的存储区大若干倍(通常是1.5到2)的新的存储区,把老的元素拷贝过去,同时完成添加或插入,然后释放老的存储区。

这就是说,vector 自动存储分配的空间大小是指数式增长的,这可以保证多次添加元素到 vector 中时,平均用时是接近于常数的。

IntVector v

// add 0, 1, ..., 99 to v:

for( int i = 0i <100++i )

v.push_back( i )

// append 9, 8, 7,..., 0 to the end:

int a[] = { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }

v.insert( v.end(), a, a + 10 )8. 删除元素

下列成员函数完成元素删除:

void erase( iterator )

void erase( iterator first, iterator last )

void pop_back()

void clear()

这些函数分别删除一个,一串,最后一个,或全部元素。

IntVector v

for( int i = 0i <100++i )

v.push_back( i )

// 删除 50, 51, ..., 89:

v.erase( v.begin() + 50, v.end() - 10 )

// 删除 49, 48:

v.pop_back()

v.pop_back()

// 全部删除:

v.clear()

注意,删除 *** 作不会引起存储分配,因此 capacity() 不变。


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/bake/11620184.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-17
下一篇 2023-05-17

发表评论

登录后才能评论

评论列表(0条)

保存