【读书笔记】Effective C++ 条款3:尽可能使用const

目录

[1. const的本质:将编译器当作你的朋友去维护一个常量](#1. const的本质:将编译器当作你的朋友去维护一个常量)

[2. 指针的const](#2. 指针的const)

[3. 迭代器的const](#3. 迭代器的const)

[4. 用const减少调用错误](#4. 用const减少调用错误)

[5. const成员函数](#5. const成员函数)

[6. bitewise观点](#6. bitewise观点)

[7. 修正:mutable](#7. 修正:mutable)

[8. Const和非const写法归一](#8. Const和非const写法归一)

详细解析

可以const调用非const吗?


1. const的本质:将编译器当作你的朋友去维护一个常量

2. 指针的const

cpp 复制代码
const char *str1 = "hello";
str1 = "ttt";  // 可以改变指针指向

在上面的代码中,const仅仅为保证str1指向的字符不被改变,但是我们可以将str1指向的内容改变。

cpp 复制代码
char str[] = "hello";
char* const str2 = str;
str2[0] = 'a';  // 可以修改内容

上面代码中的const只能维持str2指向不变,但是内容可以改变。

因此,我们要将两个const结合:

cpp 复制代码
const char* const str3 = "hello";

尽可能保证常量不被改变。在这过程中,将const作为让编译器维护常量的口令,将编译器当作你的朋友。

但是这一方案也并非天衣无缝(远古版本c++),在下面会提到

3. 迭代器的const

由于迭代器是基于指针的,也就同理,意味着有两种类型的const:const iteratorconst_iterator

  • const iterator相当于char* constT* const),指向不可变

  • const_iterator相当于const char*const T*),内容不可变

4. 用const减少调用错误

cpp 复制代码
class A
{
public:
    A(const int a = 1)
        :_a(a)
    { }
    
    A operator*(const A& aa)
    {
        A ret(_a * aa._a);
        return ret;
    }
    
    A operator=(const A& aa)
    {
        _a = aa._a;
        return *this;
    }
    
    bool operator==(const A& aa) const
    {
        return _a == aa._a;
    }
    
    operator bool()
    {
        return _a != 0;
    }
    
private:
    int _a;
};

A a(1);
A b(2);
A c(3);

在这样一个类中,如果误将if (b == c)写成if (b = c),那么你是不会察觉的。但如果加上const,那么就会报错。

5. const成员函数

在类的函数后加上const有两个作用:

  • 让函数做什么更加容易理解

  • 可以传const对象

6. bitewise观点

首先,假设有一座房子,坏没坏有种标准。bitewise观点就是只要房子外壳还是一样的,但是里面怎么坏都无所谓。这就是编译器对于const的理解:只要这块内存不动,至于内存怎么变无所谓。

这样就会发生神奇的事(远古版本c++):

cpp 复制代码
const char* const str = "hello";
char* s = &str[0];
s[0] = 'a';
cout << str << endl;

(注意:由于书本是比较老的,现在即便是c++98编译也会报错,但是由于是书中的例子,就讲究看一下吧)

同时,对于缓存,我们可能需要微小改动里面的值,即使改变了也依旧认为是const。因此也有bitewise观点认为错误,但我们需要的情况。

7. 修正:mutable

在第六点,我们发现bitewise观点很多时候并不能完全胜任

因此就需要修正

有可能我们在const函数中也需要修改值,加上mutable就可以了。

cpp 复制代码
class A
{
public:
    A(int a, int b)
        :_a(a)
        ,_b(b)
    { }
    
    int getb()
    {
        _b = 100;
        return _b;
    }
    
private:
    int _a;
    mutable int _b;
};

这就是logical constness观点。

8. Const和非const写法归一

比如[]的重载,const函数和非const函数绝大多数代码都是一样的,因此能否复用呢?可以用非const复用const。

cpp 复制代码
namespace bit
{
class string
{
public:
    string(const char* str = "")
    {
        _size = strlen(str);
        _capacity = _size;
        _str = new char[_capacity + 1];
        strcpy(_str, str);
    }
    
    char& operator[](size_t pos)
    {
        assert(pos < _size);
        assert(pos);
        return _str[pos];
    }
    
    const char& operator[](size_t pos) const
    {
        assert(pos < _size);
        assert(pos);
        return _str[pos];
    }
    
    ~string()
    {
        if (_str)
        {
            delete[] _str;
            _str = nullptr;
            _size = 0;
            _capacity = 0;
        }
    }
    
private:
    char* _str = nullptr;
    size_t _capacity = 0;
    size_t _size = 0;
    static const size_t npos = -1;
};
}

上面是简易的string类。

char& operator[](size_t pos)改为以下代码:

cpp 复制代码
char& operator[](size_t pos)
{
    return
        const_cast<char&>(
            static_cast<const bit::string&>(*this)
            [pos]
        );
}

详细解析

  1. static_cast<const bit::string&>(*this)

    其中static_cast为c++的安全转换,将*this转为const bit::string的引用。

  2. [pos]调用[]重载,返回const char

    调用const版本的operator[]。

  3. const_cast<char&>

    const_cast将常性去掉,转为char引用。

可以看到,代码繁琐冗长,因此要权衡代码可读性与简洁性。

可以const调用非const吗?

理论可以,但是调用非const就意味着需要冒着被改变的风险。

相关推荐
kylezhao20192 小时前
C#手写串口助手
开发语言·c#
Kyln.Wu2 小时前
【python实用小脚本-292】[HR揭秘]手工党点名10分钟的终结者|Python版Zoom自动签到+名单导出加速器(建议收藏)
开发语言·python·swift
普通网友2 小时前
PictureSelector 相册全白不显示问题
java·开发语言
普通网友2 小时前
用 Next.js 15 做图片查看网站:图片双击放大的交互坑与修复
开发语言·javascript·交互
独自破碎E2 小时前
kafka中的时间轮实现
java·开发语言
程序员阿鹏2 小时前
如何保证写入Redis的数据不重复
java·开发语言·数据结构·数据库·redis·缓存
JAY_LIN——82 小时前
字符串函数(strncpy/cat/cmp、strstr、strtok、strerror)
c语言·开发语言
lly2024062 小时前
C# 数据类型
开发语言
树欲静而风不止慢一点吧3 小时前
Qt5/6版本对应的Emscripten版本
开发语言·qt