当 std::initializer_list 用作赋值参数时,为什么它不是引用类型?



以下摘自C++入门第5版(第564页):

例如,除了复制和移动分配之外运算符,库向量类定义第三个赋值采用大括号元素列表的运算符(§ 9.2.5,第 337 页)。我们可以按如下方式使用此运算符:

vector<string> v;
v = {"a", "an", "the"};

我们也可以将此运算符添加到我们的 StrVec 类中(§ 13.5,第 526 页):

class StrVec {
public:
    StrVec &operator=(std::initializer_list<std::string>);
    //                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
};

在阅读时,我注意到此处使用的参数是一个值,而不是我预期的引用。所以我去了 stl 图书馆代码进行std::vector.以下是我从文件stl_vector.h中找到的内容:

  /**
   *  @brief  Builds a %vector from an initializer list.
   *  @param  __l  An initializer_list.
   *  @param  __a  An allocator.
   *
   *  Create a %vector consisting of copies of the elements in the
   *  initializer_list @a __l.
   *
   *  This will call the element type's copy constructor N times
   *  (where N is @a __l.size()) and do no memory reallocation.
   */
  vector(initializer_list<value_type> __l,
     const allocator_type& __a = allocator_type())
  : _Base(__a)
  {
_M_range_initialize(__l.begin(), __l.end(),
            random_access_iterator_tag());
  }

似乎用于 std::vector 的参数也是一个值,而不是像本书中那样的引用。但是为什么?使用引用不是更有效吗?

如果我们看一下这个 std::initializer_list 的参考,它说:

初始值设定项列表可以实现为一对指针或指针和长度。复制 std::initializer_list 不会复制基础对象。

这给了你一个关于为什么它是按值传递的强烈提示,因为复制一对指针或一个指针和一个长度并不是很昂贵。该引用实际上来自标准草案部分18.9初始值设定项列出了第 2 段。

如果我们看一下前面的提案之一,我们会发现相同的推理:

请注意,initializer_list是一个小对象(可能是两个词),因此按值传递它是有意义的。按值传递还简化了 begin() 和 end() 的内联以及 size() 的常量表达式计算。

本质上是传递

一个指针(或者更确切地说是一对指针)。当您通过引用传递指针时,在后台您将指针传递给指针。这只会增加效率低下和复杂性。

对于小型类型最有效的方法在很大程度上取决于编译器和编译选项。

尽管如此,作为一个简单的经验法则,小型内置类型参数是按值传递的,也包含由一个或两个此类值组成的小结构,而较大的内容则通过引用传递以提高效率(只是接受别名的小问题,因为它不是一个实践问题)。

最新更新