其他分享
首页 > 其他分享> > 在std :: initializer_list中的c – std :: shared_ptr似乎过早被破坏了

在std :: initializer_list中的c – std :: shared_ptr似乎过早被破坏了

作者:互联网

编辑:这确实是由Visual Studio中的错误引起的 – 它已经被修复.将Update 2应用于Visual Studio(release candidate available here)后,该问题无法重现.我道歉;我以为我和我的补丁达成了约会.

我不能为我的生活找出当我在Visual Studio 2013中运行以下代码时出现seg错误的原因:

#include <initializer_list>
#include <memory>

struct Base
{
    virtual int GetValue() { return 0; }
};

struct Derived1 : public Base
{
    int GetValue() override { return 1; }
};

struct Derived2 : public Base
{
    int GetValue() override { return 2; }
};

int main()
{
    std::initializer_list< std::shared_ptr<Base> > foo
        {
            std::make_shared<Derived1>(),
            std::make_shared<Derived2>()
        };

    auto iter = std::begin(foo);
    (*iter)->GetValue(); // access violation

    return 0;
}

我期望initializer_list获取创建的shared_ptrs的所有权,将它们保持在范围内,直到main结束.

奇怪的是,如果我尝试访问列表中的第二项,我会得到预期的行为.例如:

    auto iter = std::begin(foo) + 1;
    (*iter)->GetValue(); // returns 2

考虑到这些,我猜这可能是编译器中的一个错误 – 但我想确保我没有忽略为什么会出现这种行为的一些解释(例如,可能在初始化列表中如何处理rvalues).

这种行为在其他编译器中是否可重现,或者有人可以解释可能发生的情况?

解决方法:

请参阅original answer以分析问题中代码的对象生存期.这个隔离了这个bug.

我做了一个最小的再现.这是更多的代码,但涉及的库代码要少得多.而且更容易追踪.

#include <initializer_list>

template<size_t N>
struct X
{
    int i = N;

    typedef X<N> self;
    virtual int GetValue() { return 0; }
    X()                               { std::cerr << "X<" << N << ">() default ctor" << std::endl; }
    X(const self& right) : i(right.i) { std::cerr << "X<" << N << ">(const X<" << N << "> &) copy-ctor" << std::endl; }
    X(self&& right)      : i(right.i) { std::cerr << "X<" << N << ">(X<" << N << ">&&      ) moving copy-ctor" << std::endl; }

    template<size_t M>
    X(const X<M>& right) : i(right.i) { std::cerr << "X<" << N << ">(const X<" << M << "> &) conversion-ctor" << std::endl; }
    template<size_t M>
    X(X<M>&& right)      : i(right.i) { std::cerr << "X<" << N << ">(X<" << M << ">&&      ) moving conversion-ctor" << std::endl; }

    ~X() { std::cerr << "~X<" << N << ">(), i = " << i << std::endl; }
};

template<size_t N>
X<N> make_X() { return X<N>{}; }

#include <iostream>
int main()
{
    std::initializer_list< X<0> > foo
        {
            make_X<1>(),
            make_X<2>(),
            make_X<3>(),
            make_X<4>(),
        };

    std::cerr << "Reached end of main" << std::endl;

    return 0;
}

x64上的输出都是BAD:

C:\Code\SO22924358>cl /EHsc minimal.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 18.00.21005.1 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

minimal.cpp
Microsoft (R) Incremental Linker Version 12.00.21005.1
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:minimal.exe
minimal.obj

C:\Code\SO22924358>minimal
X<1>() default ctor
X<0>(X<1>&&      ) moving conversion-ctor
X<2>() default ctor
X<0>(X<2>&&      ) moving conversion-ctor
X<3>() default ctor
X<0>(X<3>&&      ) moving conversion-ctor
X<4>() default ctor
X<0>(X<4>&&      ) moving conversion-ctor
~X<0>(), i = 2
~X<2>(), i = 2
~X<0>(), i = 1
~X<1>(), i = 1
Reached end of main
~X<0>(), i = 4
~X<0>(), i = 3
~X<0>(), i = 2
~X<0>(), i = 1

和x86:

C:\Code\SO22924358>cl /EHsc minimal.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 18.00.21005.1 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.

minimal.cpp
Microsoft (R) Incremental Linker Version 12.00.21005.1
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:minimal.exe
minimal.obj

C:\Code\SO22924358>minimal
X<1>() default ctor
X<0>(X<1>&&      ) moving conversion-ctor
X<2>() default ctor
X<0>(X<2>&&      ) moving conversion-ctor
X<3>() default ctor
X<0>(X<3>&&      ) moving conversion-ctor
X<4>() default ctor
X<0>(X<4>&&      ) moving conversion-ctor
~X<0>(), i = 2
~X<2>(), i = 2
~X<0>(), i = 1
~X<1>(), i = 1
Reached end of main
~X<0>(), i = 4
~X<0>(), i = 3
~X<0>(), i = 2
~X<0>(), i = 1

绝对是一个编译器错误,而且非常严重.如果您提交关于Connect I的报告,许多其他人将很乐意进行投票.

标签:compiler-bug,c,visual-studio-2013,visual-c,initializer-list
来源: https://codeday.me/bug/20190830/1771514.html