CPP使用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)){
                //如果是,将子串加入path
                string 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,并且也不能在常量对象或常量引用上调用它

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值