std :: initializer_list中的std :: shared_ptr似乎被过早销毁 [英] std::shared_ptr in an std::initializer_list appears to be getting destroyed prematurely

查看:232
本文介绍了std :: initializer_list中的std :: shared_ptr似乎被过早销毁的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

修改:这确实是由Visual Studio中的错误导致的 - 它已被修复。 发布候选人在这里)。我道歉;我以为我是最新的补丁。

This is indeed caused by a bug in Visual Studio - and it has already been fixed. The issue is not reproducible after applying Update 2 to Visual Studio (release candidate available here). I apologize; I thought I was up to date with my patches.

我不能为我的生活找出为什么我当我在Visual Studio 2013中运行以下代码时遇到seg故障:

I can't for the life of me figure out why I get a seg fault when I run the following code in Visual Studio 2013:

#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_ptr 的所有权,保持它们在范围内,直到 main 结束。

I was expecting the initializer_list to take ownership of the created shared_ptrs, keeping them in scope until the end of main.

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

Oddly enough, if I try to access the second item in the list, I get the expected behavior. For example:

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

考虑到这些,我猜这可能是编译器中的错误 - 但我想确保我不会忽略一些解释为什么这个行为可能是期望的(例如,可能在如何处理在 initializer_list s)。

Considering these things, I'm guessing this may be a bug in the compiler - but I wanted to make sure I wasn't overlooking some explanation for why this behavior might be expected (e.g., maybe in how rvalues are handled in initializer_lists).

这种行为在其他编译器中是否可重现,或者有人可以解释发生了什么?

Is this behavior reproducible in other compilers, or can someone explain what might be happening?

推荐答案

有关分析问题中代码的对象生命周期的信息,请参阅原始答案。这个隔离了错误。

See the original answer for analysis of object lifetimes of the code in the question. This one isolates the bug.

我做了一个最小的复制。它是更多的代码,但更少的库代码涉及。更容易追踪。

I made a minimal reproduction. It's more code, but a lot less library code involved. And easier to trace.

#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:

The output is BAD on both x64:

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的报告,许多其他人将乐意进行upvote。

Definitely a compiler bug, and a pretty severe one. If you file a report on Connect I and many others will be happy to upvote.

这篇关于std :: initializer_list中的std :: shared_ptr似乎被过早销毁的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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