std::string() = "abc"

std::string() = "abc"

天哪?临时变量不是右值吗?怎么还能给他赋值?怪哉怪哉

在查询了多方资料后,最终被一句话点醒,“这玩意不就是一个成员函数么?”

啊这,确实,玩意不就是调用了个成员函数么。。。

果然,int() = 5;就不行,除基础类型外,赋值就相当于.operator=(),右值调用个成员函数还不是小意思,如此一来,也可以对函数返回值赋值,只要他的返回值支持operator=的重载,如

1
2
3
4
5
6
7
string foo(){
return "asd";
}
int main(){
foo() = "adff";
return 0;
}

虽然给临时变量或者函数返回值赋值没有多大意义就是了^ ^

另外还有一些奇怪的例子也是可以用操作符重载的角度来解释:

1
2
3
4
5
6
#include <iostream>
int main(){
int a[] = { 10 , 11 };
std::cout << 1 [ a ] << std::endl;
return 0;
}

上面的代码也是可以编译通过的,而且会输出11,实际上[]也就是一个双目操作符,它对于两个操作数的顺序没有严格要求,a[1]相当于*(a + 1),1[a]相当于*(1 + a),由于a在参数传递时会退化成数组首地址,所以他们是等价的

意外的收获:
在探究std::string() = “abc”的同时,还了解到了sso的概念:

1
2
3
4
5
6
7
8
9
10
11
#include <iostream>
#include <string>
void* operator new(size_t n){
std::cout<< "malloc "<<n<< " bytes\n"<<std::endl;
return malloc(n);
}
int main(){
std::string a = "0123456789ABCDE";
std::string b = "0123456789ABCDEF";
return 0;
}

Linux 5.15用clang++编译运行会输出

1
2
malloc 17 bytes

如果使用gcc则不会输出任何东西,这与编译器的底层实现有关

你可能会问,string a、b不是在栈上的东西吗?为什么会使用到new并输出这样的内容呢?

这是因为cpp标准库的string对小字符串做了优化,也就是SSO(Small String Optimization),小于等于16个字节的字符串会直接存储在栈上,大于16个字节的字符串会存储在堆上

“0123456789ABCDE\0”刚好16个字节,所以在栈上,不会用到new,而”0123456789ABCDEF\0”17个字节,所以在堆上分配了17个字节

这里的new是operator new的重载,并不是我们new一个对象的那个new,我们使用的那个new是被封装过的,在此了解

作者

Meow-2

发布于

2022-03-27

更新于

2022-06-24


评论