文章目录
- 使用示例
- const常量引用和普通引用
- 常量引用和普通引用区别示例
- 报错原因
使用示例
在 C++ 中,我们使用 const
关键字来表示一个常量,即其值在编译时就已经被设定并且在运行时不能被改变。
例如131.分割回文串,最开始传入的字符串string& s
采用了const定义
class Solution {
public:bool isPalindrome(const string& s,int start,int end){int i=start;int j=end;for(;i<j;i++,j--){ //i<j放在最后面会失效if(s[i]!=s[j])return false;}return true;}void backtracking(vector<string>&path,vector<vector<string>>&result,const string& s,int startIndex){//终止条件if(startIndex==s.size()){result.push_back(path);//加入result中return;}//单层搜索for(int i=startIndex;i<s.size();i++){//判断[start,i]这个区间的子串,是不是回文串if(isPalindrome(s,startIndex,i)){//如果是,将子串加入pathstring str = s.substr(startIndex,i-startIndex+1);path.push_back(str);//递归backtracking(path,result,s,i+1);//回溯path.pop_back();}}}vector<vector<string>> partition(string s) {vector<string>path;vector<vector<string>>result;int startIndex=0;backtracking(path,result,s,startIndex);return result;}
};
在这个问题中,字符串 s 被定义为 const
是因为我们不希望在执行算法过程中改变字符串 s 的值。
传入的参数是常量引用,这样可以保护我们的输入参数不被函数修改,并且常量引用可以提高效率,因为常量引用不会产生实参的副本。当我们处理大数据(如大型字符串或大型数组)时,这一点尤其重要。因此,const
既可以保护我们的输入数据,也可以提高函数的效率。
const常量引用和普通引用
无论是常量引用还是非常量引用,都不会产生原始数据的副本。这也是我们在处理大型数据时,为什么更愿意使用引用而不是值传递的原因。
然而,常量引用和非常量引用在功能上有一个关键的区别:
- 非常量引用(普通引用):可以通过引用来修改原始数据。
- 常量引用:不允许通过引用来修改原始数据。
用一段简单的代码来说明这个区别:
int a = 10;// Non-const reference
int &ref = a;
ref = 20; // Allowed. 'a' is now 20.// Const reference
const int &constRef = a;
constRef = 30; // Compilation error. You can't modify 'a' through 'constRef'.
当我们希望函数内部不能修改原始数据时,应该使用常量引用。
另外,如果函数参数类型是一个用户定义的类或者结构,那么常量引用和非常量引用可能会导致不同的函数(例如拷贝构造函数和拷贝赋值运算符)被调用,因此在这些情况下,选择使用常量引用还是非常量引用是非常重要的。
常量引用和普通引用区别示例
当传递类或结构体类型的数据作为参数时,实际上涉及到复制构造函数或赋值运算符。这个复制操作可能会花费相当多的时间和资源,特别是对于大型对象。引用参数则避免了这种复制,因为它们只是传递了指向已有对象的引用,而非创建了新的对象。
但这里需要注意一点,当你有一个可以修改其参数的函数,它可以接受一个非常量引用作为参数,这可能会触发一些不希望触发的行为,比如对象的复制。如下面的例子:
- const引用类对象传入函数后,函数内不能使用这个类对象的非const成员函数。
class BigObject {
public:BigObject() { std::cout << "Constructor" << std::endl; }BigObject(const BigObject& other) { std::cout << "Copy constructor" << std::endl; }BigObject& operator=(const BigObject& other) { std::cout << "Copy assignment operator" << std::endl; return *this; }void modify() { std::cout << "Modifying object" << std::endl; }
};void functionTakingNonConstReference(BigObject& obj) {obj.modify();
}void functionTakingConstReference(const BigObject& obj) {// obj.modify(); // 会发生报错,Error: cannot call non-const function on a const object
}int main() {BigObject obj;functionTakingNonConstReference(obj);const BigObject constObj;functionTakingConstReference(constObj);return 0;
}
报错原因
对于 void functionTakingConstReference(const BigObject& obj) { obj.modify(); }
这段代码,之所以会报错,是因为 modify()
函数没有被声明为 const
。这意味着它可能会(或者至少,编译器必须假设它可能会)修改它所属的对象的状态。
但是,在 functionTakingConstReference
中,obj
是一个常量const引用,这意味着我们不能通过这个const引用来修改对象。
因为,编译器不允许我们调用可能会修改对象的任何成员函数。
为了解决这个问题,如果 modify()
函数实际上并不修改对象,那么可以在其声明中添加 const
关键字,以表明这个函数不会修改其所属的对象。例如:
class BigObject {
public:void modify() const { /*...*/ }// ...
};
现在,modify
是一个常量成员函数,所以可以在常量对象或常量引用上调用它。
注意,如果 modify
函数确实需要修改对象,那么就不能将其声明为 const
,并且也不能在常量对象或常量引用上调用它。