最近发现的C++的几个“黑科技”

这篇博客探讨了C++中delete[]操作的反向析构顺序,引用变量实际上是通过编译器内部的常量指针实现,以及常量指针与指针常量的区别,并提供了使用指针常量模拟引用的示例。文章揭示了C++中一些不为人知的细节和技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

delete[]的析构顺序

先说一个小发现,在delete []的时候,是按照与构造顺序相反的顺序来析构的!(原来的构造顺序指的是,new []的时候,是按照下标顺序构造的)

#include <iostream>
using namespace std;

class Log
{
public:
    void setId(int id) {
        this->id = id;
    }

    ~Log() {
        cout << "Destruct " << id << endl;
    }

private:
    int id;
};


int main() {
    Log* logs = new Log[4];
    for (int i = 0; i < 4; ++i)
        logs[i].setId(i);

    delete [] logs;

    return 0;
}

上面代码的输出结果为:

Destruct 3
Destruct 2
Destruct 1
Destruct 0

引用变量的大小

据说编译器内部是通过“常量指针”来实现引用的,首先从它的大小来看一下:

#include <iostream>
using namespace std;

class Log
{
public:
    void setId(int id) {
        this->id = id;
    }

    ~Log() {
        cout << "Destruct " << id << endl;
    }

private:
    int id;
};

struct Wrapper
{
    Log& ref;
    Wrapper(Log log)
    : ref(log) {}
};


int main() {
    Log log;
    Wrapper w(log);
    cout << sizeof(w) << ' ' << sizeof(log) << endl;
    return 0;
}

输出结果是:8 4

8是一个指针的大小!ps,不能直接通过sizeof(ref)来判断,因为这样会输出4 4,计算的是ref所引用的对象的大小。

常量指针 VS 指针常量

下一个主题需要区分指针(类型的)常量(指向)常量(的)指针,相信看了左边括号里的注释,应该都清楚了吧?

还不清楚,只能po我自己的私藏笔记了:

常量指针,顾名思义,就是指向一个常量的指针,比如:

const int id = 555;
const int* p1 = &id;
int const* p2 = &id;

*p1 = 233;  // 错误!不允许通过指针修改变量的值,因为指向的是常量

int hello = 666;
p1 = p2 = &hello;   // 可以给指针重新赋值,指针本身不是常量

它的特点是,不能通过指针去修改所指向变量的值,常用于函数传参时声明变量内容不允许被修改(当然也可以用常引用)。

xx常量指的是这个变量是一个常量,不能修改其值,所以,“指针常量”指的就是这样的形式:

int id = 233, id2 = 555;
int* const p = &id;
id = 666;
p = &id2;// 错误!p是一个常量,不允许修改它的值
p = &id;// 错误!这样也不行,不要以为p的值等于&id就可以给它赋值,哼╭(╯^╰)╮

你可以修改原始变量的内容(只要它不是const修饰的),但是不能改变指针的值,也就是说,这个指针就只能被指定为指向这个变量了!

据说,编译器内部用常量指针来实现引用!(只是传言而已)

用指针常量来模拟引用!

直接po代码,代码清晰得,都不用解释的^_^

#include <iostream>
#include <vector>
#include <set>
#include <map>
#include <algorithm>
#include <string>
using namespace std;

class Log
{
public:
    Log(int n)
    : id(n) {}

    Log& operator = (const Log& rhs) {
        id = rhs.id;
        return *this;
    }

    void display() const {
        cout << "Log " << id << endl;
    }

private:
    int id;
};


template<typename T>
class Reference
{
private:
    /* 使用“指针常量”来模拟引用的行为:
            1) 只能绑定一个变量;
            2)必须在初始化才能使用;
            3)后续的所有赋值都是改变所绑定的变量的值。

        至于为什么是指针常量,是因为要求,这个指针不能改为指向别的变量!
    */
    T* const pointer;

public:
    Reference(T& object)
    : pointer(&object) {}

    T& operator = (T& object) {
        return *pointer = object;
    }
};


int main() {
    Log test(233);
    test.display();

    Reference<Log> ref(test);
    Log test2(666);
    ref = test2;    // 通过引用改变所绑定的值
    test.display();

    return 0;
}

输出结果是:

Log 233
Log 666

未完待续

更新于2016-08-18 15:57

jacket
于至善园4号

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值