复制std :: string时MSVC 12 std :: initializer_list错误

时间:2015-06-09 14:58:13

标签: c++ c++11 visual-studio-2013 language-lawyer msvc12

我正在尝试使用MSVC 12(Visual Studio 2013,Update 4)创建一个C ++程序,该程序使用std::initializer_list具有std::string个成员的结构。我似乎遇到了MSVC中的一个错误。这是一个展示问题的最小例子:

#include <cassert>
#include <initializer_list>
#include <string>

namespace
{
    struct TestStructure
    {
        std::string m_string;
        int m_integer;

        TestStructure(const std::string& string, int integer)
            : m_string(string), m_integer(integer)
        {
        }

        TestStructure(const TestStructure&) = default;
        ~TestStructure() = default;
        TestStructure& operator=(const TestStructure&) = default;
    };
}

int main(int, char **)
{
    TestStructure structure("foobar", 12345);
    std::initializer_list<TestStructure> structures({structure});

    assert(structure.m_integer == 12345);
    assert(structure.m_string == "foobar");
    assert(structures.size() == 1);
    assert(structures.begin()->m_integer == 12345);
    assert(structures.begin()->m_string == "foobar"); // abort()'s here.

    return EXIT_SUCCESS;
}

我希望这个程序可以毫无问题地编译和执行。但是,当我运行它时,最后一个断言似乎失败了。查看Visual Studio调试器,它似乎是structures.begin()->m_string == ""

我的程序是不是格式不正确,或者这实际上是MSVC中的错误?是否有一些解决此问题的方法(除了不使用初始化程序列表)?

1 个答案:

答案 0 :(得分:4)

问题在于您使用括号和括号:

std::initializer_list<TestStructure> structures({structure});
                                               ^^         ^^

这将构建一个临时std::initializer_list<TestStructure>并将其复制到structures;不会执行正常的生命周期扩展,因此structures将指向被破坏的存储:

<强> [dcl.init.list]

  

6 - 该数组与任何其他临时对象(12.2)具有相同的生命周期,除了从数组初始化initializer_list对象延长了数组的生命周期,就像绑定对临时对象的引用一样[.. ]

请注意,clang同意MSVC; gcc在后备阵列上执行生命周期扩展,但这样做是错误的(Bug提交:https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66476)。

如果您想要复制初始化(使用生命周期扩展),请使用等号:

std::initializer_list<TestStructure> structures = {structure};

否则,使用direct-list-initialization(直接使用大括号):

std::initializer_list<TestStructure> structures{structure};