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

更新于

2023-02-22


评论