Runtime error przy usuwaniu obiektu, plik xmemory0

0

Używam VisualStudio z biblioteką graficzną SFML.
Mam zadeklarowaną klasę:

 class Tileset
{
private:
	const sf::Color MASK_COLOR = sf::Color(255, 0, 144);

	sf::Texture texture;
	sf::Vector2i tile_size;
	int items_per_row;
	int items;
	std::string name;

	void countItems();
		
public:
	sf::IntRect getTile(int num);
	sf::Texture& getTileset() { return texture; }
	sf::Vector2i getTileSize() { return tile_size; }
	Tileset(TilesetLoadData tileset_data);
	Tileset();
	~Tileset();

	void setTexture(TilesetLoadData tileset_data);
};

Obiekt tej klasy w jednym punkcie programu tworzę dynamicznie, a w drugim chce go zwolnić:

 void Textures::init()
{
	buttons = new Tileset(BUTTONS);
	improvements = new Tileset(IMPROVEMENTS);
	fields = new Tileset(FIELDS);
	units = new Tileset(UNITS);
	misc = new Tileset(MISC);
	checkbox = new Tileset(CHECKBOX);
}

void Textures::end()
{
	delete buttons;
}

Przy usuwaniu pojawia się błąd w pliku xmemory0 w następującej funkcji:

 inline
	void _Deallocate(void * _Ptr, size_t _Count, size_t _Sz)
	{	// deallocate storage for _Count elements of size _Sz
 #if defined(_M_IX86) || defined(_M_X64)
	_SCL_SECURE_ALWAYS_VALIDATE(_Count <= (size_t)(-1) / _Sz);
	const size_t _User_size = _Count * _Sz;
	if (_BIG_ALLOCATION_THRESHOLD <= _User_size)
		{	// deallocate large block
		const uintptr_t _Ptr_user = reinterpret_cast<uintptr_t>(_Ptr);
		_SCL_SECURE_ALWAYS_VALIDATE(                         // <------------ W TEJ LINIJCE
			(_Ptr_user & (_BIG_ALLOCATION_ALIGNMENT - 1)) == 0);
		const uintptr_t _Ptr_ptr = _Ptr_user - sizeof(void *);
		const uintptr_t _Ptr_container =
			*reinterpret_cast<uintptr_t *>(_Ptr_ptr);

 #ifdef _DEBUG
		// If the following asserts, it likely means that we are performing
		// an aligned delete on memory coming from an unaligned allocation.
		_SCL_SECURE_ALWAYS_VALIDATE(
			reinterpret_cast<uintptr_t *>(_Ptr_ptr)[-1] ==
				_BIG_ALLOCATION_SENTINEL);
 #endif /* _DEBUG */

		// Extra paranoia on aligned allocation/deallocation
		_SCL_SECURE_ALWAYS_VALIDATE(_Ptr_container < _Ptr_user);

 #ifdef _DEBUG
		_SCL_SECURE_ALWAYS_VALIDATE(2 * sizeof(void *)
			<= _Ptr_user - _Ptr_container);

 #else /* _DEBUG */
		_SCL_SECURE_ALWAYS_VALIDATE(sizeof(void *)
			<= _Ptr_user - _Ptr_container);
 #endif /* _DEBUG */

		_SCL_SECURE_ALWAYS_VALIDATE(_Ptr_user - _Ptr_container
			<= _NON_USER_SIZE);

		_Ptr = reinterpret_cast<void *>(_Ptr_container);
		}
 #endif /* defined(_M_IX86) || defined(_M_X64) */

	::operator delete(_Ptr);
	}

Zrzut ekranu z błedu:

user image

Zrzut ze stosu wywołań:

user image

Wskaźnik zarówno jak metody klasy Textures są statyczne więc mam pewność, że odwołują się do tego samego.
Co jest przyczyną problemu i jak go rozwiązać?

0

Strzelam, że masz gdzieś kopię i przez to double delete. Zdefiniuj operator= i konstruktor kopiujący (rule of 3) albo postępuj zgodnie z rule of 0.

0

Albo init nie było wywołane.

0
void Textures::init()
{
    buttons = new Tileset(BUTTONS);
    improvements = new Tileset(IMPROVEMENTS);
    fields = new Tileset(FIELDS);
    units = new Tileset(UNITS);
    misc = new Tileset(MISC);
    checkbox = new Tileset(CHECKBOX);
}
 
void Textures::end()
{
    delete buttons;
}

Jak wygląda destruktor klasy Textures, a jak konstruktor kopiujący?

0

Klasa Textures wygląda tak:

 class Textures
{
private:
	static const TilesetLoadData BUTTONS;
	static const TilesetLoadData IMPROVEMENTS;
	static const TilesetLoadData FIELDS;
	static const TilesetLoadData UNITS;
	static const TilesetLoadData MISC;
	static const TilesetLoadData CHECKBOX;

	static Tileset* buttons;
	static Tileset* improvements;
	static Tileset* fields;
	static Tileset* units;
	static Tileset* misc;
	static Tileset* checkbox;

public:
	static void init();
	static void end();

	static Tileset& tilesetButtons() { return *buttons; }
	static Tileset& tilesetImprovements() { return *improvements; }
	static Tileset& tilesetFields() { return *fields; }
	static Tileset& tilesetUnits() { return *units; }
	static Tileset& tilesetMisc() { return *misc; }
	static Tileset& tilesetCheckbox() { return *checkbox; }

	Textures();
	Textures(Textures&) = delete;
	Textures(Textures&&) = delete;
	~Textures();
};

const TilesetLoadData Textures::BUTTONS = TilesetLoadData("gfx\\buttons.png", sf::Vector2i(64, 64));
const TilesetLoadData Textures::IMPROVEMENTS = TilesetLoadData("gfx\\imps.png", sf::Vector2i(40, 40));
const TilesetLoadData Textures::FIELDS = TilesetLoadData("gfx\\fields.png", sf::Vector2i(40, 40));
const TilesetLoadData Textures::UNITS = TilesetLoadData("gfx\\units.png", sf::Vector2i(20, 20));
const TilesetLoadData Textures::MISC = TilesetLoadData("gfx\\misc.png", sf::Vector2i(40, 40));
const TilesetLoadData Textures::CHECKBOX = TilesetLoadData("gfx\\checkbox.png", sf::Vector2i(256, 256));

Tileset * Textures::buttons = nullptr;
Tileset * Textures::improvements = nullptr;
Tileset * Textures::fields = nullptr;
Tileset * Textures::units = nullptr;
Tileset * Textures::misc = nullptr;
Tileset * Textures::checkbox = nullptr;

void Textures::init()
{
	buttons = new Tileset(BUTTONS);
	improvements = new Tileset(IMPROVEMENTS);
	fields = new Tileset(FIELDS);
	units = new Tileset(UNITS);
	misc = new Tileset(MISC);
	checkbox = new Tileset(CHECKBOX);
}

void Textures::end()
{
	delete buttons;
}

Textures::Textures()
{
}

Textures::~Textures()
{
}

W klasie Tileset również usunąłem konstruktor kopiujący i przenoszący ale nic się nie zmieniło.
Cały program jest skończony i działa, normalnie korzysta z dynamicznych zmiennych. Nie mogę tylko zwolnic tych zasobów podczas jego wyłączania.

Rozumiem, że w takim przypadku definiowanie konstruktora kopiującego i operatora= nic nie pomoże?

1

Może wywołujesz end kilkukrotnie?

1
FLAMESpl napisał(a):

Rozumiem, że w takim przypadku definiowanie konstruktora kopiującego i operatora= nic nie pomoże?

Zadeklaruj zmienną globalną. Nadaj jej wartość zero. Przed tym new buttons i delete buttons, odpowiednio, inkrementuj i dekrementuj tę
zmeinną globalną. W debugerze sprawdź, czy się wartość tej zmiennej wyzerowała. Jeśli się zeruje, to masz jakiś trudniejszy błąd.
Jeśli nie, to błąd jest łatwy do znalezienia, trzeba sparować new i delete.

Pozdrawiam

0

Rzeczywiście metoda została wywołana kilkuktortnie, to rozwiązuje problem. Dziękuję za odpowiedzi.

1 użytkowników online, w tym zalogowanych: 0, gości: 1