std::initializer_list 下的数组的生命周期是多少? [复制]

Posted

技术标签:

【中文标题】std::initializer_list 下的数组的生命周期是多少? [复制]【英文标题】:What is the lifetime of the array underlying a std::initializer_list? [duplicate] 【发布时间】:2015-03-16 12:43:02 【问题描述】:

按照这个答案https://***.com/a/29074955/1098041

我有一种奇怪的行为。

在调试中我得到了预期的输出,但是在发布中(我在 Windows 上使用 mingw)我在 test 函数中得到了垃圾。

#include <iostream>
#include <initializer_list>

template <class T>
struct array

    T     *ptr;
    size_t len;

    array()  clear(); 
    array( T *p, size_t l )  assign(p,l); 

    inline void clear()  ptr=nullptr; len=0; 
    inline void assign( T *p, size_t l )  ptr=p; len=l; 

    inline T& operator[] ( size_t i ) const  return ptr[i]; 
;

template <class T>
inline array<const T> wrap( std::initializer_list<T> lst )
     return array<const T>( lst.begin(), lst.size() ); 


void test( int a, int b, int c )

    auto ar = wrap(a,b,c);
    std::cout<< ar[1] << std::endl;


int main()

    auto a = wrap(1,2,3);
    std::cout<< a[2] << std::endl;

    test(1,2,3);

调试输出:

3
3

发布中的输出:

3
2686868 // some garbage.

谁能向我解释调试/发布模式如何影响 initializer_list 底层数组的生命周期? 或者为这种行为提供一些其他解释。

【问题讨论】:

可能与Strange values in a lambda returning initializer_list有关 我最初创建了这个问题,因为我发现一个奇怪的行为与问题中链接的已接受答案相矛盾,我被要求提供一个最小示例来重现我的行为。我最初虽然这是一个单独的问题,但似乎这两个问题的答案是矛盾的。现在怎么办 ?请版主帮忙。 【参考方案1】:
  auto a = wrap(1,2,3);

initializer_list(及其底层数组)的生命周期在该表达式的末尾结束,因此 a 包含一个悬空指针。

这意味着std::cout&lt;&lt; a[2] 具有未定义的行为。同样对于test 中的代码,std::cout &lt;&lt;a[1]` 也是未定义的行为。

谁能向我解释调试/发布模式如何影响 initializer_list 底层数组的生命周期?或者为这种行为提供一些其他解释。

这是未定义的行为。

任何事情都有可能发生。

在发布模式下,编译器对事物的优化方式不同,因此堆栈上的变量布局不同,因此具有未定义行为的代码可能会执行不同的操作。或者它可能不会。

这甚至不是特定于 initializer_list,对于您保存指针的 any 临时对象,您会得到类似的未定义行为:

wrap( std::vector<int>(1, 1) );

【讨论】:

所以我在main 中得到一个有效输出,但在test 中得到一个无效输出是 UB 吗?还是与第一种情况下底层数组是 constexpr 而第二种情况下它是从变量构建的事实有关? 未定义的行为意味着任何事情都可能发生!未定义的行为并不意味着它总是打印垃圾! “我得到了预期的输出”是一种可能的结果,但这并不能改变它未定义且您的程序有问题的事实。 是的,很公平。为什么一个有效而另一个无效并不重要,它是UB。顺便说一句,这个答案与我在问题中链接的公认答案完全矛盾。我虽然这是一个单独的问题,但您的回答似乎表明它不是。我要删除这个问题吗? 我已经发布了另一个问题的新答案。我认为没有任何实际需要删除此问题,但这取决于您。 为什么他有一个悬空指针?他用array&lt;const T&gt;( lst.begin(), lst.size() );复制初始化列表中的数据。

以上是关于std::initializer_list 下的数组的生命周期是多少? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

为啥 std::min(std::initializer_list<T>) 按值接受参数?

为啥 std::initializer_list 不是内置语言?

std::initializer_list 作为函数参数

如何将 C 数组转换为 std::initializer_list?

std::initializer_list 的实现

std::initializer_list 返回值的生命周期