std::initializer_list<T> 引发的关于 explicit、引用、右引用、const 的思考

事件的起因:std::initializer_list 使用时,想要提高效率,准备使用引用。

#include <utility>
#include <iostream>
#include <vector>
class Test {
public:
        std::vector<int> _arr;
public:
        Test(const std::initializer_list<int>& l) {
               for (auto it = l.begin(); it != l.end(); it++) {
                       _arr.push_back(*it);
                       std::cout << *it << ' ';
               } std::cout << std::endl;
        }
};
int main()
{
        Test test({ 1, 2, 3, 4 ,5, 6 });
}

上述代码中,Test(const std::initializer_list<int>& l)是多次试验后寻找到的 reference 的最佳使用。

以下列举思考过程的几次尝试:

1> Test(std::initializer_list<int> l) {}    -> 值传递,速度太慢

2> Test(std::initializer_list<int>& l) {}    -> error! 编译器无法匹配到 constructor(构造函数)

3> Test(std::initializer_list<int>&& l) {}    -> 右引用,引用传递,速度较快

4> Test(const std::initializer_list<int>& l) {} -> const 引用,引用传递,传递速度快


[1 … 4] 是我思考过程中,一步一步寻找的解法。

<1> 根据 cppreference.com 寻找到的 std::initializer_list class 的基本用法,但是我有点嫌弃它效率不高 ❤️
<2> 大脑的第一反应,简单:使用引用传递来代替引用传递,不就是 cpp 的基本操作嘛
但是,报错了!分析如下:

我们在使用的时候传入的实参是一个临时对象 { 1, 2, 3, 4, 5 }这样的列表,然后被 std::initializer_list<int>提供的构造函数,进行了类类型转换。

a1

现在再回头看下这句:

Test(std::initializer_list<int>{ 1, 2, 3, 4, 5, 6 });

其中的 { 1, 2, 3, 4, 5, 6 } 是常量数列,之后,再来看下面这幅图,可以知道:

  1. std::initializer_list { 1, 2, 3, 4, 5, 6 } 初始化时调用的构造函数是 35 行中那个构造。
    • 这个构造中有 2 个参数,
    • 配合 cpp 的初始化规则,肯定是将 { 1, 2, 3, 4, 5, 6 } 这个数组的首地址和末尾地址,分别传给了 _First_arg 和 _Last_arg。
  2. 代码 25 line 和 51、52 line,可以知道:
    • _First 、_Last 都是 const value_type * 类型,即:指向 const value_type 类型的指针
    • 说明 std::initializer_list 并不是我的第一印象以为的是一个转存器,而是一个访问常量数值的 iterator
  3. 代码 35 line,constexpr 修饰了这个构造函数,意味着,产生的实例对象是完全常量!

a2
OK,看完上面的分析,
为什么单纯的使用 reference 会报错了吧。
非 const 引用,意味着我们会对 std::initializer_list 的临时对象进行修改,但人家是 constexpr 类型的完全常量对象。

(嘛,咱这最后一点的论证方式,过渡的逻辑有点牵强,但是,方向和结论是绝对正确)
所以,两个种类型无法匹配到一起,自然会报错!

<3> 是咱学过的右值引用,因为右值本就是无法被修改的,当右值引用结束之后,虽然会被降格为左值引用,但是,嘛人家的生命周期只有这一句话的时间 😛
所以说,使用右值引用来引用不允许被修改的临时对象是再合适不过。的说

<4> 这就属于咱的“根性” 啦。
在 2 中,咱已经完全的论证了为啥子是失败的,
所以,这里就很好解决啦,
不让修改,那咱就使用 const 进行修改,将普通引用,修饰成 const 引用。

[全文完 ᓚᘏᗢ]

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值