Allocation of data through a list of pointers in C++ - c++

I'm trying to read the data of several objects from a file. The reading itself works fine, but I'm having trouble with writing the data into a std::list<MyObject*>. I tried a couple of things but it always ends with the application crashing after printing some stuff, which I think is random memory content. Below you can find the current version. I also tried Iterators but that didn't work either.
Here's what happens in the calling method:
PAProject proj2 = PAProject();
proj2.projectName = "myfirstOne";
PaFigureLoader::loadFigures(&proj2);
std::list<PAFigure*>::iterator figIterator;
for(figIterator = proj2.figures.begin();
figIterator != (proj2.figures.end());
figIterator++) {
PAFigure* fig = *figIterator;
if(fig->firstname.empty()) {
std::cout << "Nothing to see here\n";
break;
} else {
std::cout << fig->firstname << "\n";
}
}
The list is std::list<PAFigure*> figures
Method causing all the trouble:
static void loadFigures(PAProject *project)
{
//open input stream
fs::ifstream ifstream(filename);
std::string input;
ifstream >> input;
PAFigure * fig;
//keep a string for all the splitting:
std::string result;
//define regexs
std::regex reg1 ("(<firstname>)([a-zA-Z0-9]*)(</firstname>)");
std::regex reg2 ("(<lastname>)([a-zA-Z0-9]*)(</lastname>)");
//iterate through file to find all figures
while(input.compare("</allfigures>") != 0) {
//do the figure-loading stuff
if(input.compare("<figure>")==0) {
PAFigure newFigure = PAFigure();
project->figures.push_front(&newFigure);
fig = &newFigure;
}
//find contents
if(input.find("<firstname>")!= std::string::npos) {
std::regex_replace (std::back_inserter(result), input.begin(), input.end(), reg1, "$2");
fig->firstname = result;
result.erase();
std::cout << fig->firstname << " is firstname\n";
}
if(input.find("<lastname>")!= std::string::npos) {
std::regex_replace (std::back_inserter(result), input.begin(), input.end(), reg2, "$2");
fig->lastname = result;
result.erase();
}
//read next line
ifstream >> input;
}
PAFigure * figtest = project->figures.back();
std::cout << figtest->firstname << " last element\n";
figtest = project->figures.front();
std::cout << figtest->firstname << " first element\n";
}
Here's the output:
died
Anna is firstname
died
Dorian is firstname
Dorian last element
Dorian first element
Dorian died
Anna died
I added
PAFigure::~PAFigure()
{
std::cout << this->firstname << " died\n";
}
because I had that weird feeling that my elements were just gone, and apparently the PAFigure newFigure = PAFigure() does infact never get a firstname.
I admit that my coding experience in C++ and especially with pointer/references is very... basic. I have no idea how to solve this, not even talking about solving it in an elegant way.

Use pointer rather than reference.
Here is what's wrong:
PAFigure newFigure = PAFigure();
You should use a pointer to push, rather than reference.
PAFigure *newFigure = new PAFigure();
project->figures.push_front(newFigure);
// and create another object too.
PAFigure *fig = new PAFigure();

Related

why does the first 2 chars get skipped when executing? C++

while(!Info.eof()) {
std::getline(Info, line,'\r');
char a[line.length()];
char things[]= ":.\n\0";
for(int i=0;i<sizeof(a); i++) {
a[i]= line[i];
}
ptr = strtok(a, things);
ptr = strtok(nullptr,things);
while (ptr!= nullptr) {
ptr = strtok(nullptr,things);
std::cout << ptr << std::endl;
}
Info is the ifstream input file. line is a string. When I cout << line it displays everything no problem, the problem is i need to take away everything other than the needed strings and int, which I have done but the first 2 lines don't show. When I first executed this it displayed everything, yesterday it skipped the first line and today the first two lines. I guess this has something to do with memory or something unseen, I need help please, thanks.
Well, for starters, you are calling strtok() 3 times before your 1st cout print. So you are skipping the first few substrings.
Also, you have mistakes in your code, namely using eof() in a loop, and using non-standard variant-length arrays.
Try something more like this instead:
while (std::getline(Info, line))
{
const char *things = ":.";
ptr = strtok(line.data()/* or: &line[0]*/, things);
while (ptr)
{
std::cout << ptr << std::endl;
ptr = strtok(nullptr, things);
}
...
}
Or, as a for loop:
while (std::getline(Info, line))
{
const char *things = ":.";
for(ptr = strtok(line.data()/* or: &line[0]*/, things);
ptr != nullptr;
ptr = strtok(nullptr, things))
{
std::cout << ptr << std::endl;
}
...
}
Although, you really shouldn't be using strtok() in C++ at all. std::string has its own find_first_of() and substr() methods that you can use instead, eg:
while (std::getline(Info, line))
{
std::string::size_type start = 0, end;
while (start < line.size())
{
end = line.find_first_of(":.", start);
if (end == std::string::npos)
{
std::cout << line.substr(start) << std::endl;
break;
}
std::cout << line.substr(start, end-start) << std::endl;
start = end + 1;
}
...
}
One thing you're missing -- C-style strings are terminated with a zero on the end. You're not doing that.
Secondly, you did two strtoks before your while loop, which is why you're losing a few things.

C++: Separating a char* with '\t' delimiter

I've been fighting this problem for a while now, and can't seem to find a simple solution that doesn't involve parsing a char * by hand. I need to split my char* variable by '\t', and I've tried the following ways:
Method 1:
char *splitentry;
std::string ss;
splitentry = strtok(read_msg_.data(), "\\t");
while(splitentry != NULL)
{
std::cout << splitentry << std::endl;
splitentry = strtok(NULL, "\\t");
}
Using the input '\tthis\tis\ta\ttest'
results in this output:
his
is
a
es
Method 2:
std::string s(read_msg_.data());
boost::algorithm::split(strs, s, boost::is_any_of("\\t");
for (int i = 0; i < strs.size(); i++)
std::cout << strs.at(i) << std::endl;
Which creates an identical output.
I've tried using boost::split_regex and used "\\t" as my regex value, but nothing gets split. Will I have to split it on my own, or am I going about this incorrectly?
I would try to make things a little simpler by sticking to std:: functions. (p.s. you never use this: std::string ss;)
Why not do something like this?
Method 1: std::istringstream
std::istringstream ss(read_msg_.data());
std::string line;
while( std::getline(ss,line,ss.widen('\t')) )
std::cout << line << std::endl;
Method 2: std::string::substr (my preferred method as it is lighter)
std::string data(read_msg_.data());
std::size_t SPLITSTART(0); // signifies the start of the cell
std::size_t SPLITEND(0); // signifies the end of the cell
while( SPLITEND != std::string::npos ) {
SPLITEND = data.find('\t',SPLITSTART);
// SPLITEND-SPLITSTART signifies the size of the string
std::cout << data.substr(SPLITSTART,SPLITEND-SPLITSTART) << std::endl;
SPLITSTART = SPLITEND+1;
}

What is Causing this STATUS_ACCESS_VIOLATION?

I suck at c++ so i suspect it's a dumb mistake I have made. After a bit of research I see that that STATUS_ACCESS_VIOLATION happens when the program tries to access invalid memory blocks. That said I'm not seeing what is causing that to happen in the code below.
int main() {
cout << "!!!Hello World!!!" << endl;
Node* testNode = new Node("jhon","doe", 1, 80);
BraidedLinkedList* testList = new BraidedLinkedList();
testList->AddNode(testNode);
return 0;}
BraidedLinkedList.cpp
void BraidedLinkedList::AddNode(Node *newNode) {
if (this->start == NULL) {
this->start = newNode;
cout<<newNode->getInfo();
//the following line does not work either
//cout<<this->start->getInfo()<<endl;
}
Node.cpp
const string& Node::getInfo() {
string returnString = "";
returnString += this->getFristName() + " ";
returnString += this->getLastName() + " ";
returnString += this->getId() + " ";
returnString += this->getGrade() + " ";
}
Your 'Node::getInfo' method is returning a const reference to a temporary string object. At the point at which it attempts to print the string it's highly likely it could crash. I'm assuming you simply left out the return. In this scenario the return type should simply be 'string'.

Parsing text file into list gives segmentation fault

I'm getting a segmentation fault while trying to parse a big text file. The file contains 91 529 mRNA transcripts and details about these transcripts. I've created a RefSeqTranscript object that will take these details. When I parse the file, I create a list of these objects and start putting the details into these lists. It works fine for the first 1829 transcripts and then crashes with a segmentation fault. The method I'm running is:
void TranscriptGBFFParser::ParseFile(list<RefSeqTranscript> &transcripts, const char* filepath)
{
cout << "Parsing " << filepath << "..." << endl;
ifstream infile;
infile.open(filepath);
int num = 0;
RefSeqTranscript *transcript = new RefSeqTranscript();
for(string line; getline(infile, line); )
{
in.clear();
in.str(line);
if (boost::starts_with(line, "LOCUS"))
{
if((*transcript).transcriptRefSeqAcc.size() > 0)
{
cout << (*transcript).transcriptRefSeqAcc << ":" << (*transcript).gi << ":" << (*transcript).gene.geneName << ":" << ++num << endl;
transcripts.push_back(*transcript);
delete transcript;
RefSeqTranscript *transcript = new RefSeqTranscript();
}
}
else if (boost::starts_with(line, " var"))
{
TranscriptVariation variant;
(*transcript).variations.push_back(variant);
}
//Store the definition of the transcript in the description attribute
else if (boost::starts_with(line, "DEFINITION"))
{
(*transcript).description = line.substr(12);
for(line; getline(infile, line); )
{
if(boost::starts_with(line, "ACCESSION "))
break;
(*transcript).description += line.substr(12);
}
}
//The accession number and GI number are obtained from the VERSION line
else if (boost::starts_with(line, "VERSION"))
{
string versions = line.substr(12);
vector<string> strs;
boost::split(strs, versions, boost::is_any_of( " GI:" ), boost::token_compress_on);
boost::trim_left(strs[0]);
(*transcript).transcriptRefSeqAcc = strs[0];
(*transcript).gi = atoi(strs[1].c_str());
}
//Gene information is obtained from the "gene" sections of each transcript
else if (boost::starts_with(line, " gene"))
{
for(line; getline(infile, line); )
{
if(boost::starts_with(line.substr(21), "/gene="))
{
Gene *gene = new Gene();
string name = line.substr(27);
Utilities::trim(name, '\"');
(*gene).geneName = name;
(*transcript).gene = *gene;
delete gene;
break;
}
}
(*transcript).gene.geneID = 0;
}
else if (boost::starts_with(line, " CDS"))
{
(*transcript).proteinRefSeqAcc = "";
}
else if (boost::starts_with(line, "ORIGIN"))
{
(*transcript).sequence = "";
}
}
cout << (*transcript).transcriptRefSeqAcc << ":" << (*transcript).gi << ":" << (*transcript).gene.geneName << endl;
transcripts.push_back(*transcript);
delete transcript;
cout << "No. transcripts: " << transcripts.size() << endl;
cout << flush;
infile.close();
cout << "Finished parsing " << filepath << "." << endl;
}
I'm new to C++ and don't have a great understanding of how to work with pointers etc so I'm guessing I might have done something wrong there. I don't understand why it would work for almost 2000 objects before cutting out though.
The file I'm parsing is 2.1 GB and consists of about 44 000 000 lines so any tips on how to improve the efficiency would also be much appreciated.
This is probably not the only answer, but you have a leak...
if (boost::starts_with(line, "LOCUS"))
{
if((*transcript).transcriptRefSeqAcc.size() > 0)
{
cout << (*transcript).transcriptRefSeqAcc << ":" << (*transcript).gi << ":" << (*transcript).gene.geneName << ":" << ++num << endl;
transcripts.push_back(*transcript);
delete transcript;
// LEAK!
RefSeqTranscript *transcript = new RefSeqTranscript();
}
}
You probably mean:
transcript = new RefSeqTranscript();
It's hard to say anything specific unless you provide some more details:
What line does it crashed in?
Do you really need all of those transcripts at the same time?
But I would suggest you a couple improvements:
Don't use pointer (or at least use smart pointer) for the RefSeqTranscript *transcript;
Don't use pointer for the Gene *gene;
Generally, don't use pointers unless you realy need them;
And you have a bug here:
delete transcript;
RefSeqTranscript *transcript = new RefSeqTranscript();
Since you've laready declared transcript outside the loop's body, here you hide it with new variable with the same name. This causes memory leak, and moreover, you delete an outer transcript and do not replace it with anything. So, you probably get a crash on the next iteration.

how do i print out print out vector<string> when i get a 'compilr.com/rayd360/test-songst'

Complete program here for clarification: compilr.com/rayd360/test-songs
struct Album {
string title;
string year;
string track;
vector<string> tracks;
vector<string>::iterator trk;
}MyAlbums[40];
cout << "\n list of songs: \n";
for(int i = 0; i < 5; i++){
cout << *MyAlbums[i].trk << "\n";
}
gives me: "bash: line 1: 232 Segmentation fault "
I am needing to pass the list of tracks to a function that sorts them alphabetically then prints them out.
Any help is very much appreciated!
The line in the for loop dereferences the iterator returned by MyAlbums[i].trk. Since the iterator isn't assigned to anything (its internal pointer isn't pointing to anything) dereferencing it is Undefined Behavior. This can also cause a segmentation fault since your looking into memory that isn't owned by you.
To fix this I think you should remove the iterator from your class. Instead, use one inside your loop:
auto begin = MyAlbums.tracks.begin(),
end = MyAlbums.tracks.end();
for (auto it = begin; it != end; ++it)
{
std::cout << *it;
}
struct Album {
string title;
string year;
string track;
}MyAlbums[40];
vector<Album> tracks;
vector<Album>::iterator trk=tracks.begin();
cout << "\n list of songs: \n";
for(trk;trk!=tracks.end();++trk){
cout << *trk.title << "\n";
Assuming that you have already populated the MyAlbums.
There are two problems:
1) MyAlbums[i].trk is not initialized
2) While iterating through containers, ensure not to access container with invalid index.
(Ex: for(int i = 0; i < 5; i++) is not safe in this context).
// C++11
for ( auto track : MyAlbums.tracks )
{
cout << track << "\n";
}
// If not C++11
for (vector<string>::Iterator trackItr = MyAlbums.begin();
trackItr != MyAlbums.end(); ++trackItr)
{
cout << *trackItr << "\n";
}