我已经研究过这个问题了一段时间,我想我已经把问题缩小了。
这是错误输出
Critical error detected c0000374
Duke's Army.exe has triggered a breakpoint.
Exception thrown at 0x77E49841 (ntdll.dll) in Duke's Army.exe: 0xC0000374: A heap has been corrupted (parameters: 0x77E7C8D0).
Unhandled exception at 0x77E49841 (ntdll.dll) in Duke's Army.exe: 0xC0000374: A heap has been corrupted (parameters: 0x77E7C8D0).
The program '[14436] Duke's Army.exe' has exited with code 0 (0x0).
调用堆栈如下
ucrtbased.dll!0f8aa672() Unknown
[Frames below may be incorrect and/or missing, no symbols loaded for ucrtbased.dll]
[External Code]
> Duke's Army.exe!Tile::Tile() Line 19 C++
[External Code]
Duke's Army.exe!Map::Map(int w, int h) Line 70 C++
Duke's Army.exe!MapGenerator::init(int w, int h) Line 37 C++
Duke's Army.exe!MapGenerator::MapGenerator(int w, int h) Line 13 C++
Duke's Army.exe!PlayGameState::PlayGameState(Game * g) Line 13 C++
Duke's Army.exe!main() Line 11 C++
[External Code]
其他答案建议删除未正确声明的静态成员或类似的东西。但是,在(假设的)受影响的类中,有一个静态向量,我找不到删除的方法。有什么建议吗?
[这是我认为错误发生的类] (调用堆栈中的第19行是默认构造函数定义的开始)
Tile.h
class Tile
{
public:
static std::vector<Tile> tiles;
// Constructors and methods...
// Method used in constructors to add to static tiles
void Tile::init(const std::string& n, const sf::Color& c) {
this->name = n;
this->color = c;
tiles.push_back(*this);
}
Tile(std::string n, sf::Color c) {
init(n, c);
};
Tile() {
init("bounds", sf::Color::Black);
}
const static Tile wall;
const static Tile floor;
const static Tile bounds;
const static float TILE_SIZE;
};
静态成员在Tile.cpp中声明
std::vector<Tile> Tile::tiles = std::vector<Tile>(3);
const Tile Tile::wall("wall", sf::Color::White);
const Tile Tile::floor("floor", sf::Color::Green);
const Tile Tile::bounds;
const float Tile::TILE_SIZE = 16.f;
答案 0 :(得分:3)
您的代码默认初始化Tile::tiles
,如下所示:
std::vector<Tiles> Tile::tiles = std::vector<Tile>(3);
vector
的构造不只是设置容量,它会创建一个包含3个元素的向量,默认构造,这将导致3次调用init
,而在init
中
tiles.push_back(*this);
push_back
尝试将向量增加1,然后复制构造新添加的元素。这里的关键部分是增长矢量。
再次:记住,这是在构建矢量期间发生的。
您将创建一个超出矢量目标大小的新元素,或覆盖当前正在填充的元素。
std :: vector的GNU实现在构造函数完成之前不会设置向量大小。结果,你得到了覆盖:
#include <iostream>
#include <string>
#include <vector>
struct S {
std::string s_;
static std::vector<S> tiles;
S() { std::cout << "S()\n"; init("default"); }
S(const std::string& s) {
std::cout << "S(" << (void*) this << " with " << s << ")\n";
init(s);
}
S(const S& rhs) {
std::cout << (void*) this << " copying " << (void*)&rhs << " (" << rhs.s_ << ")\n";
s_ = rhs.s_;
s_ += " copy";
}
void init(const std::string& s) {
s_ = s;
std::cout << "init " << (void*)this << " " << s_ << "\n";
tiles.push_back(*this); // makes copy
}
};
std::vector<S> S::tiles = std::vector<S>(3);
int main() {
for (const auto& el : S::tiles) {
std::cout << el.s_ << "\n";
}
}
S()
init 0x9e67a10 default
0x9e67a10 copying 0x9e67a10 ()
S()
init 0x9e67a14 default
0x9e67a14 copying 0x9e67a14 ()
S()
init 0x9e67a18 default
0x9e67a18 copying 0x9e67a18 ()
copy
copy
copy
因此,您在应用程序启动期间引入了UB。
在上面的示例中,复制构造函数在执行复制之前默认初始化其目标,并且由于它复制自身,因此会导致rhs.s_
被清除。这就是为什么我们得到“copy
”而不是“default copy
”。
---编辑---
(无效,正如@underscore_d所指出的)
---编辑2 ---
MSVC向量实现执行此操作:
explicit vector(size_type _Count)
: _Mybase()
{ // construct from _Count * value_type()
if (_Buy(_Count))
{ // nonzero, fill it
_TRY_BEGIN
_Uninitialized_default_fill_n(this->_Myfirst(), _Count,
this->_Getal());
this->_Mylast() += _Count;
_CATCH_ALL
_Tidy();
_RERAISE;
_CATCH_END
}
}
关键部分是:
_Uninitialized_default_fill_n(this->_Myfirst(), _Count,
this->_Getal());
this->_Mylast() += _Count;
在填充过程中,你的push_back将增加_MyLast
3个位置,然后ctor的下一行将_MyLast
增加3个。
以上是在Visual Studio下运行的相同代码:http://rextester.com/WNQ21225