Skip to main content
GameDev.net gamedev.net
🔒 Locked

STL vector problem

Started by _the_phantom_ Aug 9, 2002 at 10:58 AM 14 replies 1.7k views
Original Post
_the_phantom_
_the_phantom_
I'm quite new with using the STL, so I've probably missed something really simple, however i cant for the life of me work out why what i've trying to do doesnt work. I want to create a vector of pointers to string objects, I've type def'd them like this
  
typedef vector StringList;
typedef StringList::iterator StringListItor;
  
and the varibles are stored as public class members like so (the varibles need renaming a bit, but thats the least of my worries right now)
      
StringList *m_szFadeText;			// pointer to a vector of string objects
StringListItor pFaderWriter;		// iterator for the char vector to write to it
StringListItor pFaderReader;		// iterator for the char vector to read from it
  
when my class is constructed i make a new instance of StringList and assign it to m_szFadeText
      
m_fsStatus = STAT_FREE;
m_szFadeText = new StringList;
int i = m_szFadeText->size ();
  
m_szFadeText gets a valid pointer back and 'i' correctly gets the size value of '0' now, when i come to use this vector to insert some string pointers into it using push back I use the following code
      
int i = m_szFadeText->size();
m_szFadeText->push_back(new string("< font . color=#ff0000>Phanbot says : narf. < /font>");
  
however, for some reason at this point i get an 'access violation' in the size() STL function, the pointer is still the same as it was before. also, I'm having problems getting the databack again, as this setup
      
pFaderReader = m_szFadeText->begin();
    
doesnt let me get to the string object to get teh c_str out of it (*pFaderReader)->c_str(); is allowed however if I change from a 'vector' to a 'list' (but then it crashes in the section where I push back for another reason. any help or pointers would be appricatied as its been driving me mad for the last day or so and some info that might be relavent : * the code is in a dll, and all the other functions work fine * I'm using some MFC in this DLL, however the functions that are called which call into MFC have the correct macro at the top. * I'm using VS.Net [edited by - _the_phantom_ on August 9, 2002 12:01:25 PM] [edited by - _the_phantom_ on August 9, 2002 12:36:52 PM]
daerid
daerid
Since a vector uses dynamically allocated arrays internally, why don''t you just have a vector of string object? Don''t use string pointers.

Because basically all that your array will hold is pointers to pointers, and there''s no real need for the redundancy. Just make sure your string class has the appropriate copy ctor and assignment operator. Also, refcounting the string and making it copy-on-write wouldn''t be a bad idea either.

Or you could just use std::string

oh, and use the [source][/source] tags please
daerid@gmail.com
Fruny
Fruny
Could you post your class'' code, I''m missing the context (use [source‌][/source‌] blocks). I''d also suggest you use a std::vector<std::string> instead of a std::vector<std::string*>.


Since you have a vector of pointer to strings, StringListItor acts as a pointer to a pointer to a string, which is why you must write (*itor)->c_str().

Does the ''access violation'' indicates address 0x00000000 by any chance (NULL pointer error) ?

Documents [ GDNet | MSDN | STL | OpenGL | Formats | RTFM | Asking Smart Questions ]
C++ Stuff [ MinGW | Loki | SDL | Boost. | STLport | FLTK | ACCU Recommended Books ]
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
TangentZ
TangentZ
Make sure you are linking with the CRT DLL...

*** 500 Internal Server Error ***



Kami no Itte ga ore ni zettai naru!
神はサイコロを振らない!
_the_phantom_
_the_phantom_
before I post the class code I would like to reply to a few more bits

Frunny : with regards to the (*itor)->c_str() function call, i understand that his is correct, however when trying to write this function call and using VS.Net Intellisense to help me with it, typing (*itor)-> results in an error being displayed and no drop down box when the StringList is a std::vector < std::string *>, however if I change it to an std::list < std:string *> intellisense gives me a nice drop down box with all the std::string function calls.

Tangentz : I'm probably being daft here, and i'll kick myself if its the case, but why would i want to link with the C runtime library when I'm using the C++ standard template lib?

Anyways, code follows, header first

    
#pragma once
#include <string>
#include <vector>
//#include <list>
using namespace std;


typedef vector<string *> StringList;
typedef StringList::iterator StringListItor;

#ifdef FADER_EXPORTS
#define FADER_API __declspec(dllexport)
#else
#define FADER_API __declspec(dllimport)
#endif
#ifndef __AFXWIN_H__
#error include 'stdafx.h' before including this file for PCH
#endif

#include "resource.h" // main symbols


/* functions relating to txt sending and fading using the C++ class */
// global Thread handling function

UINT ThreadSendText(LPVOID lpParam);
enum fader_status
{
STAT_FREE, // indicates the fader isnt doing anything

STAT_FADEING // indicates the fader is currently doing a fade

};

class FADER_API CFadeSend
{
public:
CFadeSend(void);
~CFadeSend(void);

// Finds the chatroom and the parts needed to fade text

bool FindChatWindow(CWnd * pParent);
// Sets up a pointer to the text to be send (Note : a local copy isnt kept, might want to at a later date)

void setTextToSend(char * pText);
// Sends the faded text (local copy) to the text window, from iOffSet into the string/array

void sendText(int iOffSet);
// Does the Fade building and sending

void doFade(void);

// Does the Fade building and sending

void doFade2(void);
int buildFade2(void);

// Status of Fade module

fader_status m_fsStatus;
// Number of lines to send

int m_iLineCount;
// Used by line count to deside if we have to turn the delay timer off or not

int m_iCurrentLine;
// Pointer to the AOL Chat window's box which contains the chat

CWnd * pAOLChatBox;
// Pointer to the Text Entry box for the AOL Chat window

CWnd * pAOLTxtEntry;
// Pointer to the text to send (Note: Local copy NOT made, might want to rethink this)

char *m_pTextToSend;
// builds the fade and setup an array containing the txt (testing reason it just builds 3 elements with static lines in it)

int buildFade(void);
// ID for the text sending thread

// char m_szFadeText[6][100];

StringList *m_szFadeText; // vector of 10 CString objects

StringListItor pFaderWriter; // iterator for the char vector to write to it

StringListItor pFaderReader; // iterator for the char vector to read from it

DWORD dwThreadId;
// handle to the thread

HANDLE hThread;
// Clean up varibles when the send is completed

void sendComplete(void);
};


Now the code to the class its self (I've stripped out anything which ISNT relivent to the current code path)

        
CFadeSend::CFadeSend(void)
: m_iLineCount(0)
, m_iCurrentLine(0)
, m_pTextToSend(NULL)
, dwThreadId(0)
{
m_fsStatus = STAT_FREE;
m_szFadeText = new StringList;
int i = m_szFadeText->size ();
}

CFadeSend::~CFadeSend(void)
{
}

// Finds the chatroom and the parts needed to fade text

bool CFadeSend::FindChatWindow(CWnd * pParent)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
// find AOL first

CWnd * pAOLWnd = pParent->FindWindow("AOL Frame25", NULL);
// now find it's MDI client

CWnd * pAOLMDIClient = pParent->FindWindowEx(pAOLWnd->m_hWnd, NULL, "MDIClient", NULL);
// pull up the first child window (should be the chat one)

CWnd * pAOLChild = pParent->FindWindowEx(pAOLMDIClient->m_hWnd, NULL, "AOL Child", NULL);
// now find the box the chat shows up in, this is on AOL7

CWnd * pAOLRichCntl = pParent->FindWindowEx(pAOLChild->m_hWnd, NULL, "RICHCNTLREADONLY",NULL); // t'is still RICHCNTL in AOL5

if (!pAOLRichCntl)
{
// no Richcntlreadonly so this aint AOL7, assume AOL5 (no info on AOL6 at this time)

pAOLRichCntl = pParent->FindWindowEx(pAOLChild->m_hWnd, NULL, "RICHCNTL",NULL); // t'is still RICHCNTL in AOL5

}
CWnd * pAOLRichCntlT = pParent->FindWindowEx(pAOLChild->m_hWnd, pAOLRichCntl->m_hWnd, "RICHCNTL", NULL);
CWnd * pAOLIcon = pParent->FindWindowEx(pAOLChild->m_hWnd , NULL, "_AOL_Icon",NULL);
CWnd * pAOLStatic = pParent->FindWindowEx(pAOLChild->m_hWnd , NULL, "_AOL_Static", NULL);
if (pAOLRichCntlT && pAOLIcon && pAOLStatic)
{
// all non-zero

pAOLChatBox = pAOLRichCntl;
pAOLTxtEntry = pAOLRichCntlT;
return true;
}
else // otherwise no chat room, bail

return false;
}


// Sends the faded text (local copy) to the text window, from iOffSet into the string/array

void CFadeSend::sendText(int iOffSet)
{
//TODO: work out why the feck we cant read back teh string objects

AFX_MANAGE_STATE(AfxGetStaticModuleState());

pFaderReader = m_szFadeText->begin();

// commented out coz as it stands this doesnt work

// pAOLTxtEntry->SendMessage(WM_SETTEXT, 0, (LPARAM)(*pFaderReader)->c_str ()); // note max send size = 232

// pAOLTxtEntry->SendMessage(WM_CHAR, 13 /*ENTER_KEY*/, 0);
// delete (*pFaderReader);
m_szFadeText->erase(pFaderReader);
}

// Does the Fade building and sending and timer setup, pCallingWindow is the window we are using to attach the WM_TIMER event to
void CFadeSend::doFade(void)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
// firstly we init and build the fade, this includes chopping it up
m_iLineCount = buildFade();
m_iCurrentLine = 0;
AfxBeginThread(ThreadSendText, this);
m_fsStatus = STAT_FADEING;
}


// builds the fade and setup an array containing the txt (testing reason it just builds 3 elements with static lines in it)
int CFadeSend::buildFade(void)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
// int i = m_szFadeText->size();
m_szFadeText->push_back(new string("< font . color=#ff0000>Phanbot says : narf. < /font>"));
// m_szFadeText->push_back(string("< font . color=#00ff00>Phanbot says : w00t. < /font>"));
// m_szFadeText->push_back(string("< font . color=#0000ff>< font . ptsize=72>Phanbot says : m00. < /font>< /font>"));
// m_szFadeText->push_back(string("<b>Narf</b><br> m00 <i>w00t</i>"));
// m_szFadeText->push_back(string("<A HREF=http://www.narf.com>narf</a>"));
/* strcpy(m_szFadeText[0],"< font . color=#ff0000>Phanbot says : narf. < /font>");
strcpy(m_szFadeText[1],"< font . color=#00ff00>Phanbot says : w00t. < /font>");
strcpy(m_szFadeText[2],"< font . color=#0000ff>< font . ptsize=72>Phanbot says : m00. < /font>< /font>");
strcpy(m_szFadeText[3],"<b>Narf</b><br> m00 <i>w00t</i>");
strcpy(m_szFadeText[4],"<A HREF=http://www.narf.com>narf</a>");
*/
// strcpy(m_szFadeText[5],"< font . color=#ff000 BACK=\"#ff00ff\" style=\"BACKGROUND-COLOR: #ff00ff\" SIZE=2 PTSIZE=10 >narf< /font>");
return 5;
}


// Thread function to send text to chat room
UINT ThreadSendText(LPVOID lpParam)
{
CFadeSend * pFadeSend = (CFadeSend *)lpParam;
while (/*pFadeSend->m_iCurrentLine != pFadeSend->m_iLineCount*/

pFadeSend->m_szFadeText->begin() != pFadeSend->m_szFadeText->end() )
{
pFadeSend->sendText(pFadeSend->m_iCurrentLine++); // send txt line and post inc

Sleep(750);
}
pFadeSend->sendComplete();
return 0;
}

// Clean up varibles when the send is completed

void CFadeSend::sendComplete(void)
{
m_fsStatus = STAT_FREE;
m_iCurrentLine = 0;
}


The code is called from a dialog box event handler thusly


        
void CchattestDlg::OnBnClickedPuttext()
{
// TODO: Add your control notification handler code here

// call routine to put text in the edit box

// no error checking at this stage

m_pFadeSend->FindChatWindow(this);
m_pFadeSend->doFade();

}


a couple of notes regarding the code, yes I'm aware it isnt very thread safe atm, but as I'm only testing ideas and can control it that doesnt matter too much right now (flags will be added later)

[edited by - _the_phantom_ on August 9, 2002 2:12:08 PM]
Fruny
Fruny
I can't see anything wrong with your code as far as the call to size() is concerned...

Suggestions though

vector::front() could replace pFaderReader : m_szFadeText->front()->c_str(); and std::deque replace std::vector since it provides std::deque::‍pop_front().

There are no reason for dynamically allocating either the strings nor the container itself in the object, since they are already intrinsically dynamic ( and you can do FadeText.push_back( "foo" ); if you really want to. )

pFadeSend->m_szFadeText->begin() != pFadeSend->m_szFadeText->end() can be replaced by !pFadeSend->empty()

Documents [ GDNet | MSDN | STL | OpenGL | Formats | RTFM | Asking Smart Questions ]
C++ Stuff [ MinGW | Loki | SDL | Boost. | STLport | FLTK | ACCU Recommended Books ]


[edited by - Fruny on August 9, 2002 3:15:50 PM]
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
TangentZ
TangentZ
quote:
Original post by _the_phantom_
Tangentz : I''m probably being daft here, and i''ll kick myself if its the case, but why would i want to link with the C runtime library when I''m using the C++ standard template lib?



You can''t new memory in EXE and try to delete
it in the DLL and vice versa. vector and other STL stuff
manages memory behind your back, so you need to be careful.

The CRT includes malloc/free , which new/delete
is based on. So you''re using the CRT even if you''re
only using C++.

*** 500 Internal Server Error ***
*** 500 Internal Server Error ***
*** 500 Internal Server Error ***



Kami no Itte ga ore ni zettai naru!
神はサイコロを振らない!
_the_phantom_
_the_phantom_
quote:
Original post by tangentz
You can''t new memory in EXE and try to delete
it in the DLL and vice versa. vector and other STL stuff
manages memory behind your back, so you need to be careful.

The CRT includes malloc/free , which new/delete
is based on. So you''re using the CRT even if you''re
only using C++.



Ah, follow you now
However, as far as I can see this dll project is setup the same as my exe project, which also make use of new/delete so unless VS.Net does something very odd when setting up DLL projects compared to EXE ones i dont think thats the problem (I have 3 projects which are part of the same solutions : an MFC exe, a standard DLL and this DLL which uses MFC via a shared DLL).
_the_phantom_
_the_phantom_
quote:
Original post by Fruny
I can''t see anything wrong with your code as far as the call to size() is concerned...

Suggestions though

vector::front() could replace pFaderReader : m_szFadeText->front()->c_str(); and std::deque replace std::vector since it provides std::deque::žpop_front().

There are no reason for dynamically allocating either the strings nor the container itself in the object, since they are already intrinsically dynamic ( and you can do FadeText.push_back( "foo" ); if you really want to. )

pFadeSend->m_szFadeText->begin() != pFadeSend->m_szFadeText->end() can be replaced by !pFadeSend->empty()



Cheers for the comments, didnt think of doing it that way with the !pFadeSend->empty()

yes, i was considering changing to a deque later, i was going to go with a vector for easy of use (haha) when it came to resizing.

The basic plan is you can dump say 10 lines into this deque/vector, and while its busy sending it you can add new lines to the end, so the thread in theory could keep running forever, as long as you kept giving it new lines (this is where the sync issues came in, but i was gonna cross that bridge later)

Anyways, i''ll take a look at my routines and probably change for a deque and remove that pointer to it and just go with an reference to the deque.
daerid
daerid
quote:
Original post by tangentz
The CRT includes malloc/free , which new/delete
is based on.


Believing that statement is just asking for trouble. The C++ standard does not define how ::operator new and ::operator delete are defined, it just defines the behavior they''re supposed to exhibit.

The fact that MS''s version uses ::malloc and ::free is just how they decided to implement it.
daerid@gmail.com
TangentZ
TangentZ
quote:
Original post by daerid
Believing that statement is just asking for trouble. The C++ standard does not define how ::operator new and ::operator delete are defined , it just defines the behavior they''re supposed to exhibit.

The fact that MS''s version uses ::malloc and ::free is just how they decided to implement it.



Hmmm... I didn''t say the C++ Standards dictates that new/delete
are to be implemented using malloc/free. Since we''re talking
about Microsoft Visual Studio .NET here, I don''t see what is
wrong about what I said.



Kami no Itte ga ore ni zettai naru!
神はサイコロを振らない!
Stoffel
Stoffel
quote:
Original post by _the_phantom_
yes, i was considering changing to a deque later, i was going to go with a vector for easy of use (haha) when it came to resizing.


You might try profiling deque against list, especially if you don''t need random access. It''s possible on your implementation that deque sacrifices efficiency for random access, and if you only need the front & back, a list might be faster. That''s something that''s easy to swap-out at any time, though.

quote:

The basic plan is you can dump say 10 lines into this deque/vector, and while its busy sending it you can add new lines to the end, so the thread in theory could keep running forever, as long as you kept giving it new lines (this is where the sync issues came in, but i was gonna cross that bridge later)


Sounds great. Container access will be need to be serialized externally with a critical section or mutex--you may know that already, just throwing it out there. =)
_the_phantom_
_the_phantom_
quote:
Original post by Stoffel
You might try profiling deque against list, especially if you don't need random access. It's possible on your implementation that deque sacrifices efficiency for random access, and if you only need the front & back, a list might be faster. That's something that's easy to swap-out at any time, though.



yeah, that was my reasoning behind using the STL and not rolling my own class to do the work.
I was gonna re-read the specs for both list and deque to see which would be more suitable, however as i do only need start or end access (one to pull off, one to put on) i might go with list as that as a pop_front() anyways


[edited by - _the_phantom_ on August 9, 2002 7:33:23 PM]
_the_phantom_
_the_phantom_
Ok, I've made some changes and I'm still getting bizzare errors.

the following code has changed (header)

    
#pragma once
#include <string>
#include <list>
using namespace std;

typedef list<string> StringList;
typedef StringList::iterator StringListItor;

class FADER_API CFadeSend
{
public:
// all the code above this point is the same as above

StringList m_szFadeText; // vector of 10 CString objects

StringListItor pFaderWriter; // iterator for the char vector to write to it

StringListItor pFaderReader; // iterator for the char vector to read from it

// all the code below this point is the same as above

};


and in the cpp file

       
int CFadeSend::buildFade(void)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
// int i = m_szFadeText->size();

m_szFadeText.push_back("< font . color=#ff0000>Phanbot says : narf. < /font>");
// m_szFadeText->push_back(string("< font . color=#00ff00>Phanbot says : w00t. < /font>"));

// m_szFadeText->push_back(string("< font . color=#0000ff>< font . ptsize=72>Phanbot says : m00. < /font>< /font>"));

// m_szFadeText->push_back(string("<b>Narf</b><br> m00 <i>w00t</i>"));

// m_szFadeText->push_back(string("<A HREF=http://www.narf.com>narf</a>"));

return 5;
}
// Thread function to send text to chat room

UINT ThreadSendText(LPVOID lpParam)
{
CFadeSend * pFadeSend = (CFadeSend *)lpParam;
while (/*pFadeSend->m_iCurrentLine != pFadeSend->m_iLineCount*/
!pFadeSend->m_szFadeText.empty () )
{
pFadeSend->sendText(pFadeSend->m_iCurrentLine++); // send txt line and post inc
Sleep(750);
}
pFadeSend->sendComplete();
return 0;
}
void CFadeSend::sendText(int iOffSet)
{
//TODO: work out why the feck we cant read back teh string objects
AFX_MANAGE_STATE(AfxGetStaticModuleState());

pFaderReader = m_szFadeText.begin();
// still cant get pFaderReader to give me a string object here via intellisense
// pAOLTxtEntry->SendMessage(WM_SETTEXT, 0, (LPARAM)(*pFaderReader)->c_str ()); // note max send size = 232
// pAOLTxtEntry->SendMessage(WM_CHAR, 13 /*ENTER_KEY*/
, 0);

// delete (*pFaderReader);

m_szFadeText.pop_front ();
}


when the constructor for the object is called the m_szFadeText is setup as following :
m_szFadeText size = 0
_MyHead = 002f6218

however, on entry to the CFadeSend::buildFade() the values have changed to the following
m_szFadeText size = 17
_Myhead = 0

also, intellisense stills says I cant get a string object reference from that StringListItor (using (*Itor) and Itor to the left of the . or -> operators)

Any ideas as to why the values should change like that? (no other functions touch the m_szFadeSend varible) and I'm still stumped on the Itor problem.

Edit: forgot to add the error when I try to use the push_back()function on the list in buildFade()
Unhandled exception at 0x2001374e (fader.dll) in chattest.exe: 0xC0000005: Access violation reading location 0x00000004.


[edited by - _the_phantom_ on August 9, 2002 7:57:15 PM]
_the_phantom_
_the_phantom_
btw, new/delete work fine in the dll as another function I was testing last nite uses them with no problems
_the_phantom_
_the_phantom_
Okies, I''ve fixed the problem, cheers to the ppl who helpped out in this thread and gave me some nice ideas to be going on with

The problem as it turns out was very simple (they always are aint they), in the constructor of my Dialogue box I new''d the FadeSend object.... and then, 2 lines later, I deleted it, thus the reason memory allocation was all over the place :o

I now feel very silly, hehe, but have now learnt something from this.

Btw, now the problem has gone away the std::list stuff works perfectly and all is good again (intellisense still cant workout the string object, but the code works so I''ll just have to deal with it the old fashioned way for now )

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.