1

Im new to programming and can't solve the following error. The dynamic allocated memory seems to be faulty. I already tried to google for people with a similar problem.

"Windows has triggered a breakpoint" at _CrtIsValidHeapPointer

Call Stack:
msvrc110d.dll!_CrIsValidHeapPointer(const void* pUserData) Line 2036
msvrc110d.dll!_free_dbg_nolock(void* pUserData, int nBlockUse) Line 1322
msvrc110d.dll!_free_dbg(void* pUserData, int nBlockUse) Line 1265
msvrc110d.dll!operator delete(void* pUserData) Line 54
Editor.exe!std::allocator<CEditbox>::deallocate(CEditbox* _Ptr, unsigned int__formal) Line 586
Editor.exe!std::_Wrap_alloc<<std::allocator<CEditbox> >::deallocate(CEditbox* _Ptr, unsigned int_Count) Line 888
Editor.exe!std::vector<CEditbox,std::allocator<<CEditbox> >::_Reallocate(unsigned int_Count) Line 1518
Editor.exe!std::vector<CEditbox,std::allocator<<CEditbox> >::_Reserve(unsigned int_Count) Line 1532
Editor.exe!std::vector<CEditbox,std::allocator<<CEditbox> >::push_back(CEditbox&&_Val)Line 851

This error occurs when a second editbox is pushed to the vector. It looks very strange to me that when i push 2 buttons to the buttons vector no error occurs, but the button class is nearly the same as the editbox class.

This is an except of the manager class

CControls

    std::vector<CEditbox> editboxes;
    std::vector<CButton> buttons;


CControls::CControls(sf::RenderWindow& paWindow, CAssetmanager& paAm) : window(paWindow), am(paAm) {
    activeControl = sf::Vector2i(0,0);
}


CControls::~CControls(void){
}

void CControls::addEditbox(int paType, sf::Vector2i paPos){
    editboxes.push_back(CEditbox(paType, paPos, window, am));
}

void CControls::addButton(int paType, sf::String paCaption,sf::Vector2i paPos){
    buttons.push_back(CButton(paType, paCaption, paPos, window,am));
}

These are the 2 other classes

CEditbox::CEditbox(int paType, sf::Vector2i paPos, sf::RenderWindow& paWindow, CAssetmanager& paAm) : window(paWindow),  font(paAm.getFont()), line(sf::RectangleShape(sf::Vector2f(2, 20))){
    active = false;
    visible = false;
    pos = paPos;

    switch(paType){//templates for editboxes
        case 1:
            maxChar = 4;
            sprite.setTexture(paAm.getTexture(2));
            sprite.setTextureRect(paAm.getTextureRect(209));

            text.setFont(font);
            text.setCharacterSize(20);
            text.setPosition(paPos.x + 5, paPos.y + 5);
            text.setColor(sf::Color::Black);

            line.setPosition(pos.x + 5, pos.y + 8);
            line.setFillColor(sf::Color::Black);
            break;
        case 2:
            maxChar = 20;
            sprite.setTexture(paAm.getTexture(2));
            sprite.setTextureRect(paAm.getTextureRect(210));

            text.setFont(font);
            text.setCharacterSize(20);
            text.setPosition(paPos.x + 5, paPos.y + 5);
            text.setColor(sf::Color::Black);

            line.setPosition(pos.x + 5, pos.y + 8);
            line.setFillColor(sf::Color::Black);
            break;
    }

    text.setString(sf::String(""));

    sprite.setPosition(pos.x, pos.y);
    size = sf::Vector2i(sprite.getTextureRect().width, sprite.getTextureRect().height);
}

CEditbox::~CEditbox(void){

}


void CEditbox::draw(){
    window.draw(sprite);
    if(active){
        window.draw(line);
    }

    if(text.getString() != ""){
        window.draw(text);
    }
}

bool CEditbox::inBounds(sf::Vector2i paPos){
    if(paPos.x > pos.x && paPos.y > pos.y && paPos.x < pos.x + size.x && paPos.y < pos.y + size.y){
        return true;
    }else{
        return false;
    }
}

void CEditbox::setVisible(bool paVisible){
    visible = paVisible;
}

bool CEditbox::isVisible(){
    return visible;
}

void CEditbox::setText(std::string paText){
    text.setString(paText);
    line.setPosition(pos.x + text.getLocalBounds().width + 5, pos.y + 8);
}

void CEditbox::setActive(bool paActive){
    active = paActive;
}

bool CEditbox::hasMaxChar(){
    if(text.getString().getSize() >= 4){
        return true;
    }else{
        return false;
    }
}


CButton::CButton(int paType, sf::String paCaption,sf::Vector2i paPos, sf::RenderWindow& paWindow, CAssetmanager& paAm) : window(paWindow),  font(paAm.getFont()){
    hover = false;
    visible = false;
    clicked = false;
    pos = paPos;

    switch(paType){//templates for buttons
        case 1:
            sprite.setTexture(paAm.getTexture(2));
            sprite.setTextureRect(paAm.getTextureRect(206));
            spriteHover.setTexture(paAm.getTexture(2));
            spriteHover.setTextureRect(paAm.getTextureRect(207));
            spriteClick.setTexture(paAm.getTexture(2));
            spriteClick.setTextureRect(paAm.getTextureRect(208));

            text.setFont(font);
            text.setCharacterSize(20);
            text.setColor(sf::Color::Black);
            break;
        case 2:
            sprite.setTexture(paAm.getTexture(2));
            sprite.setTextureRect(paAm.getTextureRect(203));
            spriteHover.setTexture(paAm.getTexture(2));
            spriteHover.setTextureRect(paAm.getTextureRect(204));
            spriteClick.setTexture(paAm.getTexture(2));
            spriteClick.setTextureRect(paAm.getTextureRect(205));

            text.setFont(font);
            text.setCharacterSize(20);
            text.setColor(sf::Color::Black);
    }

    text.setString(paCaption);
    sprite.setPosition(pos.x, pos.y);
    spriteHover.setPosition(pos.x, pos.y);
    spriteClick.setPosition(pos.x, pos.y);
    size = sf::Vector2i(sprite.getTextureRect().width, sprite.getTextureRect().height);

    //center alignment
    sf::FloatRect textRect = text.getLocalBounds();
    text.setOrigin(textRect.left + textRect.width/2.0f, textRect.top  + textRect.height/2.0f);
    text.setPosition((float)(pos.x + (size.x / 2)), (float)(pos.y + (size.y / 2)));
}


CButton::~CButton(void){
}

void CButton::draw(){
    if(clicked){
        window.draw(spriteClick);
        if(clickedFrames == 0){
            clicked = false;
        }else{
            clickedFrames -= 1;
        }       
    }else{
        if(hover){
            window.draw(spriteHover);
        }else{
            window.draw(sprite);
        }
    }


    if(text.getString() != ""){
        window.draw(text);
    }
}

bool CButton::inBounds(sf::Vector2i paPos){
    if(paPos.x > pos.x && paPos.y > pos.y && paPos.x < pos.x + size.x && paPos.y < pos.y + size.y){
        return true;
    }else{
        return false;
    }
}

void CButton::setVisible(bool paVisible){
    visible = paVisible;
}

bool CButton::isVisible(){
    return visible;
}

void CButton::setText(std::string paText){
    text.setString(paText);
}

void CButton::setHover(bool paHover){
    hover = paHover;
}

void CButton::click(){
    clicked = true;
    clickedFrames = 400;
}

Im using the default copy-constructor.

I can prevent the program from crashing, if i do "editboxes.reserve(editboxes.size() + 2);" before pushing the object to a vector, +1 wont help.

What could be the reason for this error? (sry for the unclean code)

edit: definition of editbox

#pragma once

#include <SFML/Graphics.hpp>

#include "assetmanager.hpp"


class CEditbox {
public:
    CEditbox(int paType, sf::Vector2i paPos, sf::RenderWindow& paWindow, CAssetmanager& paAm);
    ~CEditbox(void);

    void draw();
    bool inBounds(sf::Vector2i paPos);
    void setVisible(bool paVisible);
    bool isVisible();
    void setText(std::string paText);
    void setActive(bool paActive);
    bool hasMaxChar();

private:
    sf::Vector2i pos;
    sf::Font& font;
    sf::Text text;

    sf::Sprite sprite;
    sf::Vector2i size;

    int maxChar;

    bool visible;
    bool active;

    sf::RenderWindow& window;
    sf::RectangleShape line;
};
Alex
  • 13
  • 1
  • 5
  • Can you post the class definition of your `CEditbox`? The issue appears to happen when the vector has to resize in order to hold more items. I would hazard a guess that it is a double-delete scenario. – Velox Sep 09 '14 at 20:39

1 Answers1

4

The problem is not vector. The issue are the classes and types you're storing in the vector.

When you want a type to be stored in a std::vector, your requirement is that the type has proper copy semantics. In other words, if there is an issue in creating and destroying copies of a CEditbox, then vector will have a problem.

For example, does this code work properly?

int main()
{
    CEditbox e1( /* construct one */ );
    // fill e1 with some information (not shown)
    //..
    CEditbox e2 = e1;
    CEditbox e3( /*fill with parameters*/ );
    e3 = e1;
}

If that program causes issues, then you can't store CEditbox in a vector. The program above should be able to copy, assign, and destroy all three instances of CEditbox without issue (no double-deletes, no memory leaks, etc.)

I see that this link: http://sfml-dev.org/documentation/2.0/classsf_1_1Sprite.php describes the sf::Sprite class. You have instances of an sf::Sprite in your CEditbox class, and nowhere in the description of sf::Sprite does it mention that it can be copied without issue. So right there, you could be in trouble.

If the sample above does not work correctly, then I suggest that you consider using std::vector<std::unique_ptr<CEditbox>> or std::vector<std::shared_ptr<CEditbox>> -- in other words, smart pointers to your CEditbox's.

PaulMcKenzie
  • 34,698
  • 4
  • 24
  • 45
  • I believe it should be ok to copy a `sf::sprite`. SFML is a good library, and shouldn't let you copy something that doesn't support it. – Neil Kirk Sep 10 '14 at 01:05
  • FYI in C++11, the requirements for `vector` has been relaxed in many cases with move semantics. It is possible to create a `vector` of move-only objects. If it's not possible to add in move-semantics to `CEditbox`, then this answer's suggestion to use `unique_ptr` or `shared_ptr` is appropriate. – In silico Sep 10 '14 at 01:05
  • @Insilico: True but if his class doesn't support copy he should delete the copy constructor and operator=. – Zan Lynx Sep 10 '14 at 01:11
  • @NeilKirk - I took a look at the `sf::sprite` header here: http://sfml-dev.org/documentation/2.0/Sprite_8hpp_source.php There is a pointer member, so I don't know if it is safe to copy. – PaulMcKenzie Sep 10 '14 at 01:18
  • Sprites have a pointer to an external texture resource that must be managed seperately. – Neil Kirk Sep 10 '14 at 02:04
  • I tried your copy, assign, destroy code and it doesn't work because of no "operand=" is available. I can't even write it myself, because it's no member of CEditbox. – Alex Sep 10 '14 at 08:27
  • Moreover i used the shared_ptr, but have problems, as you suggested, with my sf::Sprite. Prescisely: a access violation, reading sf::Drawable, __vfptr and sf::Transformable, __vfptr (both type void**). This occurs after window.draw(sprite).I checkeck the stack and found out: __vfptr gets unable to read, after "text.setFont(font)", right behind the textureRect assignment. All other properties seem to be ok. The textures should be managed right, and i couldn't find any issue in the assetmanager, which handles the textures. I couldn't find anything about vfptr on google or the documentation. – Alex Sep 10 '14 at 08:40
  • @Alex In my test, remove the `e3` lines and see if it compiles and runs correctly. Second, I'm suggesting that you use a `CEditbox *`, not `CEditbox`. The smart pointer is just a safer construct than a raw pointer, but the concept is the same. The point being that your classes cannot be copied safely with the way they are now -- there are pointers to resources that need to be managed, and you can't merely copy one CEditbox to another using copy construction (as my small code should demonstrate). – PaulMcKenzie Sep 10 '14 at 10:02
  • @PaulMcKenzie I'm confused. i tried two things: 1) "std::vector editboxes;" and editboxes.push_back(new "CEditbox(paType, paPos, window, am));" and 2)"std::vector> editboxes;" and " editboxes.push_back(std::shared_ptr(new CEditbox(paType, paPos, window, am)));" which both end in unreadable memory issue. To my (newbie) mind, a new instance of CEditbox is created, saved in the Heap and then I point to it with either the smart or a raw pointer, therefore no copy would be needed. Where is my error in reasoning? I see that i have to avoid copying. – Alex Sep 10 '14 at 11:15