无法加载ntdll.dll

时间:2016-08-05 20:32:36

标签: c++ c++11 static global sfml

我已经研究过这个问题了一段时间,我想我已经把问题缩小了。

这是错误输出

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;

1 个答案:

答案 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";
    }
}

输出http://ideone.com/0dr7L2

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