trouble with STL list initialization inside nested structure

M

M A

Hi,

Please see following code.
It gives me segmentation fault when I try to add element to the list
on the very last line. I am not sure why the "bm" list inside MyStruct
is not getting initialized? What can I do to initialize it?

Thanks.

-------------------------------------------
#include <stdio.h>
#include <list>
#include <vector>
#include <iostream>
#include <algorithm>

using namespace std;

struct row {
int rowid;
char *data;
bool operator<(const struct row &a) const {
return (this->rowid < a.rowid);
};

};
typedef struct {
list<struct row> bm;
vector<struct row> vbm;
} MyStruct;

typedef struct pattern {
int nodenum; // unique in the graph
MyStruct ms;
} TP;

int main(int args, char **argv)
{
TP *tp = (TP *) malloc (sizeof(TP));

struct row r1 = {1, (char *)"xyz"};

tp->ms.bm.push_back(r1);
}

-------------------------------------------
 
J

Joshua Maurice

Hi,

Please see following code.
It gives me segmentation fault when I try to add element to the list
on the very last line. I am not sure why the "bm" list inside MyStruct
is not getting initialized? What can I do to initialize it?

Thanks.

[snip code]
TP *tp = (TP *) malloc (sizeof(TP));
this is not the same as
TP *tp = new TP;
The first does not call any constructors. The second calls TP::TP, the
constructor, which also calls the constructor of all sub-objects,
including the std::list member sub-object. Without calling the
constructor of std::list, attempting to do anything with it is
undefined behavior. std::list::list() constructor sets up invariants
and internal data members.

You seem to be coming from a C background. I'd suggest a picking up a
good book on C++.
 
M

M A

Thanks for the explanation Joshua. I wasn't aware of intricate
differences between "malloc" and "new"!
I just made a quick fix as follows:
------------------------------------

typedef struct pattern {
int nodenum; // unique in the graph
MyStruct ms;
} TP;

int main(int args, char **argv)
{

TP *tp = new TP;

struct row r1 = {1, (char *)"xyz"};

tp->ms.bm.push_back(r1);

list<struct row>::iterator itr = tp->ms.bm.begin();

cout << (*itr).rowid << " " << (*itr).data << endl;
}
-------------------------------------
And it is working now.
Thanks a lot for your help. :)


Please see following code.
It gives me segmentation fault when I try to add element to the list
on the very last line. I am not sure why the "bm" list inside MyStruct
is not getting initialized? What can I do to initialize it?

[snip code]
TP *tp = (TP *) malloc (sizeof(TP));

this is not the same as
  TP *tp = new TP;
The first does not call any constructors. The second calls TP::TP, the
constructor, which also calls the constructor of all sub-objects,
including the std::list member sub-object. Without calling the
constructor of std::list, attempting to do anything with it is
undefined behavior. std::list::list() constructor sets up invariants
and internal data members.

You seem to be coming from a C background. I'd suggest a picking up a
good book on C++.
 
F

Francesco S. Carta

Thanks for the explanation Joshua. I wasn't aware of intricate
differences between "malloc" and "new"!
I just made a quick fix as follows:
------------------------------------

typedef struct pattern {
        int nodenum; // unique in the graph
        MyStruct ms;

} TP;

int main(int args, char **argv)
{

        TP *tp = new TP;

        struct row r1 = {1, (char *)"xyz"};

        tp->ms.bm.push_back(r1);

        list<struct row>::iterator itr = tp->ms.bm.begin();

        cout << (*itr).rowid << " " << (*itr).data << endl;}


Consider replacing C-style strings with std::string - if you really
come from a C background you will have to put apart some of the tricks
needed by C. Most of the explicit memory management gets done behind
the curtains by the STL containers, take advantage of them, when you
write in C++.

Also, learn to replace all C-style casts with C++ explicit casts -
you'll learn also that most of the times you don't need casting at
all. For example, conversions get normally done with functional
notation:
-------
int i = 10;
double d = double(i) / 3;
-------

Once I'm here: don't top post. It messes up replies and some users
gets a bit upset for them.

You can learn a lot of things about C++ and about comp.lang.c++ by
reading the FAQ: http://www.parashift.com/c++-faq-lite/

Have good time,
Francesco
 
S

SG

M said:
typedef struct {
        list<struct row> bm;
        vector<struct row> vbm;

} MyStruct;

This is a mixture of C and C++. You could write just as well

struct MyStruct {
list<row> bm;
typedef struct pattern {
        int nodenum; // unique in the graph
        MyStruct ms;
} TP;

same here
int main(int args, char **argv)
{
        TP *tp = (TP *) malloc (sizeof(TP));
        struct row r1 = {1, (char *)"xyz"};
        tp->ms.bm.push_back(r1);
}

same here. Replace malloc with new and char* with std::string. Also, I
don't see a reason for using the free store. This should work too:

int main(int args, char **argv)
{
TP tp;
row r1 = {1, "xyz"}; // note: no "struct" prefix
tp.ms.bm.push_back(r1);
}

By the way: In C++ string literals are const. So, you better use
"const char*" instead of "char*". The latter one still compiles for
backwards compatibility to C. Since you're now allowed to modify the
characters of a string literal (not even in C) you'll only gain from
using const qualifiers here.

One last note: Try to improve encapsulation.

Cheers,
SG
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,576
Members
45,054
Latest member
LucyCarper

Latest Threads

Top