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

按照这个答案https://stackoverflow.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 底层数组的生命周期? 或者为这种行为提供一些其他解释。

【问题讨论】:

  • 我最初创建了这个问题,因为我发现一个奇怪的行为与问题中链接的已接受答案相矛盾,我被要求提供一个最小示例来重现我的行为。我最初虽然这是一个单独的问题,但似乎这两个问题的答案是矛盾的。现在怎么办 ?请版主帮忙。

标签: c++ debugging release 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() );复制初始化列表中的数据。
猜你喜欢
  • 2021-09-25
  • 2013-02-23
  • 2011-09-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多