std :: initializer_list中的std :: shared_ptr似乎被过早销毁 [英] std::shared_ptr in an std::initializer_list appears to be getting destroyed prematurely
问题描述
修改:这确实是由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_ptr
s, 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_list
s).
这种行为在其他编译器中是否可重现,或者有人可以解释发生了什么?
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屋!