this指针和sort的爱恨情愁
起因
楼主在刷剑指offer的时候遇到了这么一道题,把数组排成最小的数,这是题的地址。解题思路无非就是先根据新的排序规则对原数组进行排序,然后在遍历生成数即可。我们知道,C++的STL库sort非常好用,其重载形式也多种多样,而sort重载版本的第三个参数是一个二元谓词(即只接受两个参数)。于是机智的楼主很快码出来了下面的代码:
class Solution {
public:
string minNumber(vector<int>& nums) {
sort(nums.begin(), nums.end(), comp);
string ans = {};
for (const auto &c : nums)
ans += to_string(c);
return ans;
}
bool comp(int &a, int &b) {
string sa = to_string(a), sb = to_string(b);
return sa + sb < sb + sa;
}
};
正当楼主意气风发,F5运行准备剑指offer时,编译器却向我展示了一个致命错误:

看着这陌生的错误,我心想看来offer只能剑指了,但是我注意到了一个东西,即第三条error:应输入两个参数,却提供了三个。懵逼的我再一次看了看我的可调用对象,心想没毛病啊。但是我知道没毛病是因为我修行不够,需要向场外老哥求助,于是我向场外老哥进行了求助。果然,经验丰富的老哥一眼就看出了错误所在,函数定义了在了类里面,this指针就是那多出的参数。当时的我恍然大悟,对啊,非静态成员函数都会包含一个this指针引用,方便对对象进行各种处理。
为了验证猜测,机智的我把函数定位了static模式,这样编译器就不会加上所谓的this指针了,结果如下:

果不其然,静态属性屏蔽掉this指针后,也就不会存在所谓的参数错误了。那么问题来了,不加static的函数实则是什么模式呢?这就得谈到this指针的成员函数了。
this指针和成员函数的爱恨情仇
一个类的非静态成员函数实则是属于每一对象本身,也就是我们得通过对象去调用他自己的成员函数,而不是类本身。假设我们有这么一个类:
class A{
int a=0;
public:
int test(){
return a;
}
};
int main(){
A a;
cout<<a.test();
}
这里我们通过对象a调用它本身的test函数,得到其成员变量的值。实际上当我们调用成员函数时,是在替某个对象调用它。即成员函数通过一个名this的额外隐参来访问调用它的对象,也就是说我们刚刚实际上返回的是A.a,其调用关系等价:A::test(&a)。即编译器负责将对象地址传递给了成员函数的隐式形参,注意这里虽然是隐式形参,但本质上还是一个参数,它也会占用参数数目。而我们知道静态成员函数是属于类本身,为所有对象所共享,所以调用静态成员函数并不需要使用this指针来区分,因为这就独一份。
所以真相水落石出,成员函数的this指针破坏了参数的结构。所以明白了为什么,我们也可以通过其他手段修改上述代码,比如lambda表达式,bind绑定等等。
lambda表达式版本
class Solution {
public:
string minNumber(vector<int>& nums) {
sort(nums.begin(), nums.end(), [](int &a, int &b) {
string sa = to_string(a), sb = to_string(b);
return sa + sb < sb + sa;
});
string ans = {};
for (const auto &c : nums)
ans += to_string(c);
return ans;
}
};
bind绑定参数版本
using namespace std;
using placeholders::_1;
using placeholders::_2;
class Solution {
public:
string minNumber(vector<int> &nums) {
sort(nums.begin(), nums.end(), bind(&Solution::comp, this, _1, _2));
string ans;
for (const auto &c : nums) ans += to_string(c);
return ans;
}
bool comp(int &a, int &b) {
string sa = to_string(a), sb = to_string(b);
return sa + sb < sb + sa;
}
};
用bind的时候,可别忘了声明占位符
总结
当我们在类里面想使用STL库函数,并且想自己定义函数对象时,千万别忘了this指针也成员函数占用参数的,所以最佳办法还是使用lambda表达式或者static静态声明,毕竟bind太复杂了。
3274

被折叠的 条评论
为什么被折叠?



