2016-08-05 4 views
-3

Я изучил этот вопрос некоторое время, и я думаю, что я сузил проблему.Не удается загрузить ntdll.dll

Это ошибка выхода

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; 
}; 

Static члены объявлены в 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

Я не думаю, что проблема будет в любом коде декларации. Проверьте свои конструкторы и методы. –

+0

'const Tile Tile :: xxxx' должен быть' const Tile :: xxxx' –

+1

@ Jean-FrançoisFabre Ум. Я так не думаю. Эти члены (три из них) являются объектами 'Tile', статичными для класса' Tile' (что разрешено). – WhozCraig

ответ

3

Ваш код по умолчанию инициализирует Tile::tiles так:

std::vector<Tiles> Tile::tiles = std::vector<Tile>(3); 

Это строительство vector не просто установить емкость, он создает вектор, содержащий 3 элемента, по умолчанию constructored, что приведет к 3 вызовов init, и в init вы

tiles.push_back(*this); 

push_back попытки вырастить вектор по одному, а затем скопировать-построить новый добавленный элемент. Ключевой частью здесь является расти вектор.

Снова: помните, что это происходит во время построения вектора.

Вы либо создадите новый элемент за пределами целевого размера вектора, либо перепишете элемент, который в настоящее время заполняется.

Реализация GNU std :: vector не устанавливает размер вектора до тех пор, пока конструктор не будет завершен. В результате вы получаете перезаписывает:

#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».

--- Edit ---

(недействительный, как указал @underscore_d)

--- Edit 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

+0

@ user4581301 Да - см. Также мое редактирование о стене, полу и потолке. – kfsone

+0

«порядок инициализации не определен» только между разными единицами перевода. Эти 2 переменные определены в одном ТУ. В этом случае, как и в случае с любыми другими «статическими» объектами, порядок инициализации гарантированно будет соответствовать порядку определения. Ваш последний раздел кажется несущественным. –

+0

@ user4581301 См. Раздел edit 2, а также ссылку на онлайн-версию тестовой программы на Visual Studio. – kfsone

Смежные вопросы