在我的项目中,我使用静态对象的构造函数收集指针,就像注册方法一样。很简单,没有魔法。但是在开始的时候,我经历了一次车祸,我无法解释这里发生了什么。这种崩溃在使用MSVC或Clang的Windows上是可重复的,它们都使用MSVC报头。给出了下面的简单示例。有人能告诉我为什么这会引起问题吗?
在Linux上的GCC和Clang中,这段代码似乎工作得很好:
https://gcc.godbolt.org/z/vSKdpW
bar.cpp
static int bar = 1;
static Registration abc(&bar);foo.cpp
static std::vector<void*> registrations;
void add_to_array(void* p)
{
registrations.push_back(p);
}foo.h
class Registration
{
public:
Registration(void* op)
{
add_to_array(op);
}
};在以下崩溃中执行结果(_Pnext为0x8)。
void _Orphan_range(pointer _First, pointer _Last) const { // orphan iterators within specified (inclusive) range
#if _ITERATOR_DEBUG_LEVEL == 2
_Lockit _Lock(_LOCK_DEBUG);
_Iterator_base12** _Pnext = &_Mypair._Myval2._Myproxy->_Myfirstiter;
while (*_Pnext) { <======================= **_Pnext** was 0x8.有人知道为什么不能使用静态向量来简单地收集指向对象的指针吗?foo.cpp是唯一使用push_back的向量的文件。数组不会在其他地方被修改。
发布于 2020-06-27 03:58:08
在使用VS2019运行时调试了类似的问题之后,我将继续说,这几乎可以肯定是由零初始化(但不是构造)向量造成的。
在我的例子中,法医看起来是这样的:_Pnext的值是0x8,因为_Myproxy是空的。当_ITERATOR_DEBUG_LEVEL设置为2(即:在调试概要文件中)时,_Myproxy将被取消引用,从而导致此崩溃,但是发行版不会崩溃,因为该代码被完全跳过。
现在,查看MSVC142 142/ is 2019的向量实现,您将看到每个构造函数都调用_Alloc_proxy,这就是为_Myproxy分配一些内存并分配值的方法。因此,如果已经调用了构造函数,则必须有一个非空_Myproxy。
C++中的静态初始化分两个步骤进行:零初始化,然后以任意链接器确定的顺序进行静态初始化。看起来,按照结束的顺序,foo.cpp的Registration在Bar.cpp的registrations向量之前被构造,实际上是在零初始化(但不是构造)向量上调用push_back。
因此,正如注释所建议的那样,您肯定应该重新安排静态初始化,以便在使用之前正确地构造向量。
(在我的例子中,我为包含向量的结构分配内存,但没有在该内存上调用placement operator new。对于任何像我一样发现这个问题的人,都要寻找零向量的任何来源,而不是构造向量。)
https://stackoverflow.com/questions/61809337
复制相似问题