c++26新功能—带花括号初始化器的静态存储

一、大括号的初始化

做为使用大括号进行初始化即使用std::initializer_list进行列表初始化时,会让整个程序看起来更加的清晰明了,实现也相对简单。但这种实现的过程中,会出现各种情况。虽然在整体上,都会生成一个临时的数组来进行数据的存储,但在不同的情况下,C++对其实现的细节也各有不同。随着C++标准的演进,有些实现已经可以进一步的进行优化。本文介绍的静态存储即是如此。

二、存在的问题

在上面提到的不同的情况会有一些不同的处理机制,那么可以对下面的两种实现进行一下对比:

struct X {
  X(std::initializer_list<double> v);
};
X x{ 1,2,3 };

这种情况下,对其的展开其实就是将相关的数组数据(1,2,3)存储在静态存储区中。这种情况下,效率和内存应用就相对要好很多。但再看一下这个例子:

void f(std::initializer_list<int> il);

void g() {
    f({1,2,3});
}

int main() { g(); }

在这种情况下,则不一定将展开的临时数组存储在静态区域中,重点看f函数的实现,比如下面的代码:

void g();

void f(std::initializer_list<int> il) {
    static const int *ptr = nullptr;
    if (ptr == nullptr) {
        ptr = il.begin();
        g();
    } else {
        assert(ptr != il.begin());
    }
}

这是因为标准(C++23及以前)要求两次调用(第一次调用f和在g函数中回调再次调用f)时,其应该具备不同的地址,所以此时两次展开的临时数组(1,2,3)则不能够存储在静态存储中。同样,如果在类似于STL中的容器实现中也有类似的情况:

std::vector<int> vec = {6,7,8,9,10};

这种情况下,数据会进行两次拷贝,即从静态存储到栈,然后再从栈到堆。如果说上面的这种情况,数据量小的情况下,代价并不大。但如果有开发者想在向量中存储一个图像数据怎么办?

三、如何解决

针对上面的问题,在C++26版本前,可以使用前面学习过的#embed方法来嵌入相关的二进制数据,防止数据的拷贝,如:

static const char backing[] = {
    #embed "2mb-image.png"
};
std::vector<char> v = std::vector<char>(backing, std::end(backing));

而在C++26中提议使用:

std::initializer_list<int> i1 = {
    #embed "very-large-file.png"  // 可以
};

void f2(std::initializer_list<int> ia,
        std::initializer_list<int> ib) {
    PERMIT(ia.begin() == ib.begin()); // 允许 ia.begin() == ib.begin()
}
int main() {
    f2({1,2,3}, {1,2,3});
}
//或者如下面的代码
const char *p1 = "hello world";
const char *p2 = "world";
PERMIT(p2 == p1 + 6);  // 当前的行为

std::initializer_list<int> i1 = {1,2,3,4,5};
std::initializer_list<int> i2 = {2,3,4};
PERMIT(i1.begin() == i2.begin() + 1);  // 提议的未来的行为

其实就是新标准希望常量初始化的初始化列表避免占用栈空间。也就是说,在列表初始化时,不管原来多少次的数组拷贝,都可以被公共使用,这样就会减少拷贝的次数,大大提高了效率。

四、总结

其实对开发者来说,本文更重要的是对C++标准实现的编译内部细节的说明。其实它也是对C++安全和效率机制的一种更新,可能这样做对开发者的影响并不多大。毕竟,很多程序员自己在写代码时对内存的浪费和多次拷贝并不多敏感。但从标准的角度来看,应用开发者可以自由处理,但底层的基础建筑可不能这样,否则就显得有点水平跟不上了。
正如前面所讲,开发者学习的最好的资料和例子就是标准的实现,他们才是最接近于C++标准完美实现的榜样。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值