c++ - 引用/initializer_list 的生命周期

标签 c++ c++11 g++ initializer-list clang++

考虑以下示例:

第一个编译单元:

#include <vector>
#include <string>
#include <initializer_list>
#include <iostream>

struct DoubleString
{
  std::string one;
  std::string two;
};

class E
{
  public:
  E(std::initializer_list<DoubleString> init) : stringVec(std::move(init))
  {}

  void operator()()
  {
    for (auto const & x : stringVec)
    {
      std::cout << x.one << " " << x.two << std::endl;
    }
  }

  private:
    std::initializer_list<DoubleString> stringVec;
};

class F
{
  public:
    F( const std::string & one, const std::string & two) : e{ {one, two} }
    { }

    void operator()()
    {
      e();
    }

  private:
    E e;
};

class Caller
{
  public:
    void operator[](F f);
};


int main()
{
  Caller()[ F{"This is string 1", "This is string 2"} ];
}

独立编译单元:

void Caller::operator[](F f)
{
  f();
}

另见 http://coliru.stacked-crooked.com/a/b01d349fa8f22f62

用 gcc 和 clang 编译和运行这个,两个片段在一个编译单元中,输出是 "这是字符串 1 这是字符串 2"

当我将 void Caller::operator [](F f) 移动到一个单独的编译单元时,它仍然适用于 gcc,但会因 clang 而中断(它会打印垃圾)。 Clang 地址清理器检测到:

==16368==ERROR: AddressSanitizer: stack-buffer-underflow on address 0x7ffc6602f388 at pc 0x0000006d036a bp 0x7ffc6602f340 sp 0x7ffc6602f338

当我使用 std::vector 作为变量 E::stringVec 的类型时,它再次适用于 clang。

看来我误用了 std::initializer_list。是否允许将其用作变量?为什么它适用于 gcc 但不适用于 clang?

顺便说一句:我喜欢 Coliru 作为在线编译器。有谁知道,如何定义单独的编译单元?

最佳答案

原文std::initializer_list<DoubleString>作为 F 的构造函数调用的一部分创建(将其传递给成员 e 时)。创建此 std::initializer_list<DoubleString>DoubleString对象被创建。 std::initializer_list<DoubleString>的生活因此,DoubleString e 时对象结束成员完成初始化。

然而,std::initializer_list<T>不是真正的值类型。它是可复制的,但拷贝不会创建拷贝,而只是将堆栈指针复制到用于创建 std::initializer_list<T> 的对象。 .这个,复制在E实际上指向一系列对象(好吧,只有一个),一旦原始 st::initializer_list<DoubleString> 被销毁消失了。也就是说,您只有未定义的行为。为什么事情在一种情况下有效而不是另一种情况并不十分清楚,但这在某种程度上是未定义行为的本质。

基本要点是:std::initializer_list<T>不是真正的一等公民。从本质上讲,这是一种获取堆栈分配对象序列而不复制它们以允许序列初始化的技巧。它确实在参数列表之外没有任何位置,参数列表应该能够使用无限数量的相同类型的参数。

关于c++ - 引用/initializer_list 的生命周期,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34649928/

相关文章:

c++ - 对于不断添加和删除的一组元素,我应该使用哪个容器

c++ - 由于创建新对象,C++ 中内存不足

c++ - 禁止带有 `static_assert` 的函数

c++ - GNU Make 产生完全不同的结果

c++ - 尺寸非常大的二维 vector

c++ - 使用 new 放置移动构造对象

c++ - std::ofstream 的无序映射

c++ - 模板元编程示例没有意义

c++ - 可变参数模板中的模糊运算符[]

c++ - VS 代码 C++ : inaccurate system includePath errors (wchar. h,boost/lambda/lambda.hpp)