C++STL中swap函数操作与内存地址改变的简析

个人博客链接:C++ STL中swap函数操作与内存地址改变的简析 | Iwts’s blog

写在前面

这篇文章主要讨论了STL中swap函数在交换2个容器的内容的时候是交换内存还是交换元素的问题。由于博主对C++的学习并不好,如果有什么错误恳请大家提出。下面会有一些代码展示一下swap函数在对容器进行交换的时候对内存地址的影响,感兴趣的同学也可以自己写一下代码,会更加直观理解swap函数。

N年不写cpp了,贴一个评论

首先你的string打印地址的方式有问题 要么你用printf("%p")来输出,如果用cout的话需要这样,static_cast<void*>(&a[0]),其次,当然是会交换指针的,不然一个很大的string对象swap岂不是要赋值,那不就太扯淡了吗,只不过问题在 string内部不全是放在堆上的,比如windows下会有个char buf[16] 当字符串长度小于16的时候是放在栈上的,那样的话 swap就只能拷贝了,但是超过16个字节,就放在堆上,就会有交换 比如代码如下:

{
        std::string a("abc");
        std::string b("def");
 
        std::cout<<static_cast<void*>(&a[0])<<std::endl;
        std::cout<<static_cast<void*>(&b[0])<<std::endl;
 
        a.swap(b);
        std::cout<<static_cast<void*>(&a[0])<<std::endl;
        std::cout<<static_cast<void*>(&b[0])<<std::endl;
    }
    {
        std::string a("askdflsdjfsdljfsdlkfjslfjsdlfjkalsjfsdlfkjsdflsjdflsdkjeljrqlwekjrwlfjdslfjsdflsdkfjsldfkjsd");
        std::string b("askdflsdjfsdljfsdlkfjslfjsdlfjkalsjfsdlfkjsdflsjdflsdkjeljrqlwekjrwlfjdslfjsdflsdkfjsldfkjsd");
 
        std::cout<<static_cast<void*>(&a[0])<<std::endl;
        std::cout<<static_cast<void*>(&b[0])<<std::endl;
 
        a.swap(b);
        std::cout<<static_cast<void*

上面的代码会打印出如下信息,可以看到当字符串长度超过16后,确实会交换指向堆上内存的指针的

0x7fff3311c200
0x7fff3311c220
0x7fff3311c200
0x7fff3311c220
0x918120
0x917e50
0x917e50
0x918120

先放结论

swap函数会交换2个数据类型相同的容器内容。本身交换的速度非常快,因为swap在交换的时候并不是完全将2个容器的元素互换,而是交换了2个容器内的内存地址。除了数组,其他容器在交换后本质上是将内存地址进行了交换,而元素本身在内存中的位置是没有变化的。换而言之,如果说有2个房间,名字是a和b,那么swap函数交换的是2个房间的名字,而房间里的物品根本没有任何移动。那么外部指向物品的指针当然也没有任何变化,原来指向物品A的,swap交换后仍然指向物品A。而对于数组,

对vector使用swap函数

#include<iostream>
#include<string>
#include<vector>
#include<map>
#include<algorithm>

using namespace std;

int main() {
	int a[3] = { 1,2,3 };
	int b[3] = { 4,5,6 };
	vector<int> v1(a, a + 3);
	vector<int> v2(b, b + 3);
	cout << "v1中各个元素的地址:" << endl;
	for (int i = 0; i < 3; i++) {
		cout << &v1[i] << " ";
	}
	cout  << endl << "v2中各个元素的地址:" << endl;
	for (int i = 0; i < 3; i++) {
		cout << &v2[i] << " ";
	}
	int *temp = &v1[2];
	cout << endl << "temp指针指向的数据值:" << endl << *temp;
	cout << endl << endl;
	swap(v1, v2);
	cout << "v1中各个元素的地址:" << endl;
	for (int i = 0; i < 3; i++) {
		cout << &v1[i] << " ";
	}
	cout << endl << "v2中各个元素的地址:" << endl;
	for (int i = 0; i < 3; i++) {
		cout << &v2[i] << " ";
	}
	cout << endl << "temp指针指向的数据值:" << endl << *temp;
	cout << endl;

	system("pause");
	return 0;
}

下面是在博主计算机上的运行结果:

可以看出,v1与v2的各个元素的地址进行了交换,换而言之就是v1与v2的“名字”进行了交换,而里面的元素该在什么地址仍然在什么地址。

对数组使用swap函数

#include<iostream>
#include<string>
#include<vector>
#include<map>
#include<algorithm>

using namespace std;

int main() {
	int a[3] = { 1,2,3 };
	int b[3] = { 4,5,6 };
	cout << "a数组中各个元素的地址:" << endl;
	for (int i = 0; i < 3; i++) {
		cout << a + i << " ";
	}
	cout << endl << "b数组中各个元素的地址:" << endl;
	for (int i = 0; i < 3; i++) {
		cout << b + i << " ";
	}
	int *temp = a + 2;
	cout << endl << "temp指针指向的数据值:" << endl << *temp;
	cout << endl << endl;
	swap(a, b);
	cout << "a数组中各个元素的地址:" << endl;
	for (int i = 0; i < 3; i++) {
		cout << a + i << " ";
	}
	cout << endl << "b数组中各个元素的地址:" << endl;
	for (int i = 0; i < 3; i++) {
		cout << b + i << " ";
	}
	cout << endl << "temp指针指向的数据值:" << endl << *temp;
	cout << endl;

	system("pause");
	return 0;
}

下面仍然是在博主计算机上运行的结果:

可以看到,对数组进行swap交换后,地址是不变的,也就是说,对于数组,swap函数老老实实将所有的元素进行了交换。房间名不变,将里面的物品交换了位置。对于temp指针而言,temp指向的地址永远是不变的,但是由于交换了元素,所以temp指向的内存地址的数据发生了变化。可以理解为a房间是海尔饮水机,b房间是三星饮水机,temp指向的永远是a房间的饮水机,那么swap交换后,a房间的饮水机变成了三星的,那么temp指向的当然也变成三星饮水机了。

string

以下内容是之前不知道在哪里看的,因为博主不是搞C++的,当时参考的其他内容,并没有过于深究准确性,因为解决了个人问题,所以认为是正确的了。但是不够严谨,推荐大家专门看一下string的源码或者咨询其他搞C++的大佬。欢迎大家看下面的内容,有错误的地方可以评论改正。

string是比较特殊的,因为string的底层实现比较特殊。博主水平不够,就只能参考其他大佬的解释口胡了。

string在调用swap后,迭代器、引用、指针都会失效。因为string的内部实现并不是像C语言自己写的char数组,而是用_Ptr这个指针来储存字符串,指向的是字符串的首地址。字符串是储存在临时内存区域中的,也就是说,在进行交换后,内存会重新分配。所以之前的指针、迭代器等都会失效,因为它们指向的内存地址并不会随着字符串的改变而改变。

关于_Ptr这个指针,我的理解是指向字符串的内存开始,可以参考下面这个代码:

#include<iostream>
#include<string>
#include<vector>
#include<map>
#include<algorithm>

using namespace std;

int main() {
	string a = "abc";
	string b = "def";
	for (int i = 0; i < 3; i++) {
		cout << &a[i] << " ";
	}
	cout << endl;
	for (int i = 0; i < 3; i++) {
		cout << &b[i] << " ";
	}
	cout << endl << endl;
	swap(a, b);
	for (int i = 0; i < 3; i++) {
		cout << &a[i] << " ";
	}
	cout << endl;
	for (int i = 0; i < 3; i++) {
		cout << &b[i] << " ";
	}
	cout << endl;

	system("pause");
	return 0;
}

而运行结果如下:

并不是想象中的给出内存地址,而是给出了3个字符串,因为这里得到的是_Ptr指针的内容,所以返回的是3个字符串。

  • 10
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值