返回initializer_list的lambda中的奇怪值 [英] Strange values in a lambda returning initializer_list

查看:206
本文介绍了返回initializer_list的lambda中的奇怪值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请考虑此 C ++ 11 代码段:

  #include< iostream& 
#include< set>
#include< stdexcept>
#include< initializer_list>


int main(int argc,char ** argv)
{
enum Switch {
Switch_1,
Switch_2,
Switch_3,
Switch_XXXX,
};

int foo_1 = 1;
int foo_2 = 2;
int foo_3 = 3;
int foo_4 = 4;
int foo_5 = 5;
int foo_6 = 6;
int foo_7 = 7;

auto get_foos = [=](切换ss) - > std :: initializer_list< int> {
switch(ss){
case Switch_1:
return {foo_1,foo_2,foo_3};
case Switch_2:
return {foo_4,foo_5};
case Switch_3:
return {foo_6,foo_7};
默认值:
throw std :: logic_error(invalid switch);
}
};

std :: set< int> foos = get_foos(Switch_1);
for(auto&& foo:foos){
std :: cout< foo< ;
}
std :: cout<< std :: endl;
return 0;
}

无论我尝试什么编译器,都似乎处理不正确。



clang 3.5 输出:

这是一个错误,而不是多个编译器的常见错误。

  -1078533848 -1078533752 134518134 


$ b b

gcc 4.8.2 输出:

  -1078845996 -1078845984 3 
输出 .tutorialspoint.com> http://www.tutorialspoint.com ):

  1 2 267998238 

gcc(未知版本)http://coliru.stacked-crooked.com )

  -1785083736 0 6297428 

问题似乎是由使用 std: :initializer_list< int> 作为lambda的返回值。当将lambda定义更改为 [=](切换ss) - > std :: set< int> {...}



请帮我解决这个谜。

解决方案

发件人: http://en.cppreference.com / w / cpp / utility / initializer_list


底层数组不保证在原始初始化列表的生命周期后存在对象已结束。 std :: initializer_list的存储是未指定的(即它可以是自动,临时或静态只读存储器,取决于情况)。


我不认为初始化器列表是可复制构造的。 std :: set 和其他容器。基本上看起来你的代码的行为类似于返回一个临时的引用。



C ++ 14有一些略微不同的底层存储 - em>其生命周期 - 但这并不能解决任何与 initializer_list 对象的生命周期有关,更不用说副本。因此,即使在C ++ 14中,问题依然存在。


底层数组是一个临时数组,从原始初始化器列表的相应元素初始化(除非变窄转换无效)。底层数组的生命周期与任何其他临时对象相同,除了从数组初始化initializer_list对象之外,还可以延长数组的生命周期,就像绑定临时的引用(具有相同的例外,例如用于初始化非静态类成员)。底层数组可以分配在只读存储器中。



Consider this C++11 code snippet:

#include <iostream>
#include <set>
#include <stdexcept>
#include <initializer_list>


int main(int argc, char ** argv)
{
    enum Switch {
        Switch_1,
        Switch_2,
        Switch_3,
        Switch_XXXX,
    };

    int foo_1 = 1;
    int foo_2 = 2;
    int foo_3 = 3;
    int foo_4 = 4;
    int foo_5 = 5;
    int foo_6 = 6;
    int foo_7 = 7;

    auto get_foos = [=] (Switch ss) -> std::initializer_list<int> {
        switch (ss) {
            case Switch_1:
                return {foo_1, foo_2, foo_3};
            case Switch_2:
                return {foo_4, foo_5};
            case Switch_3:
                return {foo_6, foo_7};
            default:
                throw std::logic_error("invalid switch");
        }
    };

    std::set<int> foos = get_foos(Switch_1);
    for (auto && foo : foos) {
        std::cout << foo << " ";
    }
    std::cout << std::endl;
    return 0;
}

Whatever compiler I try, all seem to handle it incorrectly. This makes me think that I am doing something wrong rather than it's a common bug across multiple compilers.

clang 3.5 output:

-1078533848 -1078533752 134518134

gcc 4.8.2 output:

-1078845996 -1078845984 3

gcc 4.8.3 output (compiled on http://www.tutorialspoint.com):

1 2 267998238

gcc (unknown version) output (compiled on http://coliru.stacked-crooked.com)

-1785083736 0 6297428 

The problem seems to be caused by using std::initializer_list<int> as a return value of lambda. When changing lambda definition to [=] (Switch ss) -> std::set<int> {...} returned values are correct.

Please, help me solve this mystery.

解决方案

From: http://en.cppreference.com/w/cpp/utility/initializer_list

The underlying array is not guaranteed to exist after the lifetime of the original initializer list object has ended. The storage for std::initializer_list is unspecified (i.e. it could be automatic, temporary, or static read-only memory, depending on the situation).

I don't think the initializer list is copy-constructable. std::set and other containers are. Basically it looks like your code behaves similar to "returning a reference to a temporary".

C++14 has something slightly different to say about the underlying storage - extending its lifetime - but that does not fix anything having to do with the lifetime of the initializer_list object, let alone copies thereof. Hence, the issue remains, even in C++14.

The underlying array is a temporary array, in which each element is copy-initialized (except that narrowing conversions are invalid) from the corresponding element of the original initializer list. The lifetime of the underlying array is the same as any other temporary object, except that initializing an initializer_list object from the array extends the lifetime of the array exactly like binding a reference to a temporary (with the same exceptions, such as for initializing a non-static class member). The underlying array may be allocated in read-only memory.

这篇关于返回initializer_list的lambda中的奇怪值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆