赞
踩
STL容器所提供的都是值(value)寓意,而非引用(reference)寓意,也就是说当我们给容器中插入元素的时候,容器内部实施了拷贝动作,将我们要插入的元素在另行拷贝一份放入到容器中,而不是将原数据直接放入到容器中,也就是说我们提供的元素必须能够被拷贝(自己写的指针的话,就需要自己写一个拷贝构造函数;如果是一个类,会调用拷贝构造函数※)。
1.除了Queue和Stack之外,每个容器都提供可返回迭代器的函数,运用返回的迭代器就可以访问元素
2.通常STL不会抛出异常,需要使用传入正确的参数
3.每个容器都提供了一个默认的构造函数和默认的拷贝构造函数
4.大小相关的构造方法:1.size()返回容器中元素的个数 2.empty()判断容器是否为空。
如果发生扩容,会拷贝就元素到扩容后的里面,然后析构原有元素
参考:STL-vector
此时如果有浅拷贝发生,会出现析构问题!
流程:
https://blog.csdn.net/u012501459/article/details/44132147
https://zohead.com/archives/vector-push-back-space-copy/
- #include <iostream>
- #include <vector>
- #include <list>
-
- using namespace std;
-
- class Base {
- public:
- Base(vector<int> vec,list<int> list):m_vec(vec),m_list(list){};
- ~Base(){
- cout<<"destroy class"<<endl;
- };
- Base(const Base& base)
- {
- m_list = base.m_list;
- m_vec = base.m_vec;
- cout<<"copy class"<<endl;
- };
- private:
- vector<int> m_vec;
- list<int> m_list;
- };
-
- int main()
- {
- vector<int> vec1 (5,0);
- list<int> list1(3,1);
- Base base1(vec1,list1);
- Base base2(vec1,list1);
-
- cout<<"push_back list:"<<endl;
- list<Base> m_listGroup;
- m_listGroup.push_back(base1);
- m_listGroup.push_back(base2);
-
- cout<<"push_back vector:"<<endl;
- vector<Base> m_vectGroup;
- m_vectGroup.push_back(base1);
- m_vectGroup.push_back(base2);
- cout<<"end test"<<endl;
- }
push_back list:
copy class
copy class
push_back vector:
copy class
copy class
copy class
destroy class
end test
destroy class
destroy class
destroy class
destroy class
destroy class
destroy class
结果分析
vector 每次调用 push_back 时都会拷贝一个新的参数指定的 sss 类对象,这会调用 sss 的拷贝构造函数,第一次的 copy 正常,而且 vector 的实际容量也由 0 变为 1。
第二次调用 push_back,通过输出会发现调用了两次拷贝构造函数,一次析构函数,原来 vector 此时判断容量不够,将容量扩大为原来的两倍,变为 2,并将原来的元素再次拷贝一份存放到新的内存空间,然后拷贝新加的类对象,最后再释放原来的元素。
第三次调用 push_back 时,vector 自动扩大为4,因此拷贝构造函数调用了3次,析构函数调用了2次,程序最终退出了时就析构了 5 次加本身的 sss 类对象一共 6 次。
- #include <vector>
- #include <iostream>
-
- using namespace std;
-
- typedef struct point{
- int x;
- int y;
- }Point;
-
-
-
- ostream& operator<<(ostream& output, const Point &a)
- {
- return output << a.x <<" "<< a.y;
- }
-
- int main(){
-
- Point * a = new Point;
- vector<Point> PointList;
-
-
- a->x = 3;
- a->y = 4;
- PointList.push_back(*a);
-
- a->x = 4;
- a->y = 4;
- PointList.push_back(*a);
-
- a->x = 5;
- a->y = 4;
- PointList.push_back(*a);
-
- delete a;
-
- for (vector<Point>::iterator i = PointList.begin(); i != PointList.end(); i++){
- cout << (*i)<< endl;
- }
-
- return 0;
- }
这说明完成的不是将a的地址加入到vector,而是将数据整个拷贝了一份加入进去
- #include<iostream>
- #include<vector>
- using namespace std;
-
- //深拷贝和浅拷贝的问题
- #if 0
- class Person
- {
- public:
- Person(const char* name,int age)
- {
- this->pName = new char[strlen(name) + 1]; //开辟内存
- strcpy(this->pName, name); //值拷贝
- this->pAge = age;
- }
-
- //只写上面的会出现程序宕掉,原因是出现了两次析构
- //解决办法,写一个拷贝构造
- Person(const Person& p)
- {
- this->pName = new char[strlen(p.pName) + 1];
- strcpy(this->pName, p.pName);
- this->pAge = p.pAge;
- }
- //重载等号
- Person& operator=(const Person& p)
- {
- //先释放空间,然后在拷贝
- if (this->pName != NULL)
- {
- delete[] this->pName;
- }
-
- this->pName = new char[strlen(p.pName) + 1];
- strcpy(this->pName, p.pName);
- this->pAge = p.pAge;
-
- return *this;
- }
- ~Person()
- {
- if (this->pName != NULL)
- {
- delete[] this->pName;
- }
- }
- public:
- char* pName; //指针
- int pAge;
- };
-
- void test01()
- {
- Person p("aaa", 21);
- vector<Person> vPerson;
- vPerson.push_back(p);
- }
-
- #endif
-
- class Person2
- {
- public:
- Person2(char* s)
- {
- pStr = s;
- }
- Person2() {}
- /*Person2& operator=(const Person2 p)
- {
- pStr = p.pStr;
- return *this;
- }*/
- Person2& operator=(const Person2& p)
- {
- if (strlen(pStr) != strlen(p.pStr))
- pStr = new char[strlen(p.pStr) + 1]; //为被赋值对象申请了一个新的内存
- /*if (*this != p)
- strcmp(p.pStr, p.pStr);*/
- return *this;
- }
- public:
- char* pStr;
- };
-
- void test02()
- {
- Person2 p2("aaa"),p3; //上面不加const这里报错,加了const后上面的=报错
- p3 = p2;
- cout << p2.pStr << endl;
- cout << p3.pStr << endl;
- }
-
- int main()
- {
- //test01();
- test02();
-
- system("pause");
- return 0;
- }
读取vector内的元素,如果赋值给其他变量,是将对象复制一份新的。
Item ii = list[0];
如果直接操作数组元素,是不会产生对象复制的
list[0].a
是值传递,vector本身,及vector内的所有元素都会复制一遍。
得不偿失,可以使用引用传递。
c++中常用的vector容器作为参数时,有三种传参方式,分别如下(为说明问题,用二维vector):
注意,三种方式分别有对应的const形式,不在此讨论。
三种方式对应的调用形式分别为:
三种方式的效果分别为:
不会创建新vector对象的。函数内返回的跟接收返回值的是一个对象。
读取vector内的元素,如果赋值给其他变量,是将对象复制一份新的。
- #include <stdlib.h>
- #include <stdio.h>
- #include <vector>
-
- class Item{
- public:
- int a;
- int b;
- };
-
- std::vector<Item> vectorTestFunc(std::vector<Item> input){
-
- printf("vectorTestFunc >>> in %p %p, %p\n",&input, &input[0], &input[0].a);
- Item item = input[0];
-
- std::vector<Item> output;
- output.push_back(item);
- printf("vectorTestFunc <<< in %p %p, %p\n",&output, &output[0], &output[0].a);
- return output;
- }
- int main(int argc, char* argv[]){
- std::vector<Item> list;
- Item i;
- i.a = 1;
- i.b =2;
- printf("i adr is %p, %p\n",&i, &i.a);
- list.push_back(i);
- printf("list[0] adr is %p, %p\n",&list[0], &list[0].a);
-
- Item ii = list[0];
- printf(" ii adr is %p, %p\n",&ii, &ii.a);
-
-
-
- printf("vectorTestFunc in %p %p, %p\n",&list, &list[0], &list[0].a);
- std::vector<Item> output = vectorTestFunc(list);
-
- printf("vectorTestFunc output %p %p, %p\n",&output, &output[0], &output[0].a);
- return 0;
- }
build$ make; ./main
Scanning dependencies of target main
[ 50%] Building CXX object CMakeFiles/main.dir/main.cpp.o
[100%] Linking CXX executable main
[100%] Built target main
i adr is 0x7ffc5a16b160, 0x7ffc5a16b160
list[0] adr is 0x5583c3b0f280, 0x5583c3b0f280
ii adr is 0x7ffc5a16b168, 0x7ffc5a16b168
vectorTestFunc in 0x7ffc5a16b170 0x5583c3b0f280, 0x5583c3b0f280
vectorTestFunc >>> in 0x7ffc5a16b1b0 0x5583c3b0f2a0, 0x5583c3b0f2a0
vectorTestFunc <<< in 0x7ffc5a16b190 0x5583c3b0f2c0, 0x5583c3b0f2c0
vectorTestFunc output 0x7ffc5a16b190 0x5583c3b0f2c0, 0x5583c3b0f2c0
如果把函数参数改成引用:
build$ make; ./main Scanning dependencies of target main [ 50%] Building CXX object CMakeFiles/main.dir/main.cpp.o [100%] Linking CXX executable main [100%] Built target main i adr is 0x7ffe81b1cf40, 0x7ffe81b1cf40 list[0] adr is 0x5641c6771280, 0x5641c6771280 ii adr is 0x7ffe81b1cf48, 0x7ffe81b1cf48 vectorTestFunc in 0x7ffe81b1cf50 0x5641c6771280, 0x5641c6771280 vectorTestFunc >>> in 0x7ffe81b1cf50 0x5641c6771280, 0x5641c6771280 vectorTestFunc <<< in 0x7ffe81b1cf70 0x5641c67712a0, 0x5641c67712a0 vectorTestFunc output 0x7ffe81b1cf70 0x5641c67712a0, 0x5641c67712a0
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。