【发布时间】:2014-04-07 22:35:35
【问题描述】:
编辑:这确实是由 Visual Studio 中的一个错误引起的 - 它已经被修复。 将 Update 2 应用到 Visual Studio (release candidate available here) 后,该问题无法重现。我道歉;我以为我的补丁是最新的。
我一生都无法弄清楚为什么在 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_ptrs 的所有权,将它们保持在范围内直到 main 结束。
奇怪的是,如果我尝试访问列表中的第二项,我会得到预期的行为。例如:
auto iter = std::begin(foo) + 1;
(*iter)->GetValue(); // returns 2
考虑到这些事情,我猜这可能是编译器中的一个错误——但我想确保我没有忽略一些解释为什么会出现这种行为(例如,可能是如何处理右值) initializer_lists)。
这种行为在其他编译器中是否可以重现,或者有人可以解释可能发生的情况吗?
【问题讨论】:
-
如果您使用析构函数(例如使用
std::cerr或OutputDebugString),您是否会遇到同样的失败?如果行为仍然存在,析构函数是否提前运行? -
似乎与 g++ 4.7 一起工作正常。可能会增加您的分析,即编译器可能存在问题。
-
请注意,
shared_ptr可能会被销毁。std::shared_ptr<Base>对象通过转换临时std::shared_ptr<Derived1>(和 2)对象来初始化。但这不应该导致Derived1(和2)对象本身的死亡,因为在shared_ptr转换期间每个对象的引用计数应该达到2。或者也许移动构造函数用于转换并且引用计数被盗。 -
并不是说这有多大帮助,但同样可以在 clang++ 上正常工作(调试和所有); (Apple LLVM 版本 5.1 (clang-503.0.38)(基于 LLVM 3.4svn))。 g++ 4.8 也是如此。
-
感谢其他编译器的所有信息。 @BenVoigt 这是有道理的。我曾尝试使用调试器进入一些 MSFT 标头以更好地了解正在发生的事情,但很快就迷失了自己。作为一个额外的数据点:如果我像这样在列表中创建 4 个项目,则访问前 两个 会导致访问冲突。
标签: c++ visual-c++ visual-studio-2013 initializer-list compiler-bug