views:

85

answers:

4

I have a class Message that has a std::string as a data member, defined like this:

class Message
{
// Member Variables
    private:
        std::string text;
        (...)

// Member Functions
    public:
        Message(const std::string& t)
        : text(t) {}

        std::string getText() const {return text;}
        (...)
};

This class is used in a vector in another class, like this:

class Console
{
// Member Variables
    private:
        std::vector<Message> messageLog;
        (...)

// Member Functions
    public:
        Console()
        {
            messageLog.push_back(Message("Hello World!"));
        }

        void draw() const;
};

In draw(), there's an iterator that calls getText(). When it does, the program segfaults. I've determined that text is valid inside the Message constructor. However, I can't tell if it's valid from inside Console. I'm assuming it is, but if I try to inspect indices of Console's messageLog, gdb tells me this:

(gdb) p messageLog[0]
One of the arguments you tried to pass to operator[] could not be converted to what the function wants.

Anyone know what's going on?

EDIT: here's draw(). TCODConsole is part of a curses library I'm using, and so this function prints each message in Console to a part of the curses screen. TL and BR are Point member objects (two ints) that tell where on the screen to draw Console. I left out parts of Message and Console in the original question to hopefully make things clearer, but if you need me to post the entire classes then I can. They aren't too long.

void Console::draw() const
        {
            int x = TL.getX(), y = TL.getY();
            int width = BR.getX() - TL.getX();
            int height = BR.getY() - TL.getY();

            // draw the Console frame
            TCODConsole::root->printFrame(x, y, width, height, true);

            // print the Console's messages
            vector<Message>::const_iterator it;
            for(it=messageLog.begin(); it<messageLog.begin()+height-1; ++it)
            {
                string message = "%c" + it->getText();
                TCODConsole::setColorControl(TCOD_COLCTRL_1, 
                                             it->getForeColor(),
                                             it->getBackColor());
                y += TCODConsole::root->printRectEx(x, y, width, height,
                                                    TCOD_BKGND_NONE,
                                                    TCOD_LEFT,
                                                    message.c_str(),
                                                    TCOD_COLCTRL_1);
            }
        }
A: 

Is it definitely std::vector messageLog and not std::vector<Message> messageLog? That seems a bit odd.

t0rx
That was a typo. It is `std::vector<Message> messageLog`.
Max
it dropped the `<Message>` part of the line because SO apparently thought it was a tag. Is there a way to stop it from doing that within <pre><code> tags?
Max
@Max: Stop using `<pre><code>` tags to format code. SO does not display such code correctly (the angle brackets in particular). Use the formatting buttons instead.
AndreyT
A: 

It's probably because the scope of the Message object created in the Console method is just the Console method. So, if your program is trying to access this object in another method, like draw, you will get this segmentation fault, since this object is deleted after the execution.

Try this (just insert a new keyword):

    Console()
    {
        messageLog.push_back(new Message("Hello World!"));
    }

In this case, the object is not deleted after Console's end.

Just remember to delete the objects created when your program doesn't need them anymore.

Juliano
`push_back` will construct a copy of its argument, which has lifetime until the `std::vector` is destroyed or the element is removed or overwritten.
Ben Voigt
+1  A: 

My guess is that by the point you use it->getText(), the iterator is NULL. Add a check it != messageLog.end() when you walk the array, and before calling it->getText().

rturrado
This was the problem. I was so focused on thinking about a `Console` with 500+ elements, I didn't think about it with only one. Thanks.
Max
A: 

What does the height have to do with the vector's index? You have:

messageLog.begin()+height-1;

Why are you adding the screen coordinate to the iterator? That seems to be your problem and you're most likely overindexing and that's why you're getting a SIGSEGV.

What you probably want is to simply iterate over all the messages in the vector and display them at a particular location on the screen. I see what you're trying to do, but if you're trying to calculate the screen boundary using the iterator you're definitely going about it the wrong way. Try running a counter or get messageLog.size() and then recalculate the height with each iteration. As for the loop just do:

for(it=messageLog.begin(); it!=messageLog.end(); ++it)
zdawg