Vector containing struct with pointer

Started by
6 comments, last by Sneftel 15 years, 2 months ago
This is probably a pointer problem, but I can't find a workaround this one. All I'm trying to do is create a vector of structs, then accessing a pointer in that struct via the vector, but I can't seem to do that. Here's the gist of my code:

typedef struct b
{
    int num;
} b_t;

typedef struct a
{
    b_t *b_p;
} a_t;

typedef struct main
{
    vector<a_t> *vec;
} main_t;

int main()
{
    main_t *test = new main_t;
    a_t* parent = new a_t;
    b_t* member = new b_t;
    member->num = 3;

    parent->b_p = member;

    test->vec = new vector<a_t>(1);

    test->vec->push_back(*parent);

    cout << test->vec->at(0).b_p->num << endl;
}


Before you ask why I'm using structs, I'm using a file which was previously written in C. I'd expect it should still work.
Advertisement
So what's the problem? Compile error? Runtime error? The ghosts of Gilbert and Sullivan possessing your computer?
The program crashes when it gets to the cout line.
Shortly after I posted I realised I didn't clear the vector before using push_back, would that be a problem?
Quote:Original post by SiCrane
The ghosts of Gilbert and Sullivan possessing your computer?


I hate when that happens. Stupid undefined behavior.

C++: A Dialog | C++0x Features: Part1 (lambdas, auto, static_assert) , Part 2 (rvalue references) , Part 3 (decltype) | Write Games | Fix Your Timestep!

Quote:Original post by Demolit
Shortly after I posted I realised I didn't clear the vector before using push_back, would that be a problem?
No. A Vector's initial state is empty.

The first thing that jumps out at me about that code is that you should never new up a vector. Just declare the vector as a member of the struct (remove the *).
The cause of the crash though, is that you're adding 1 uninitialised item to the vector when you're newing it and the one you're pushing back is then put after the uninitialised one, at index 1, not 0.

Some fixed code:
typedef struct b{    int num;} b_t;typedef struct a{    b_t *b_p;} a_t;typedef struct main{    vector<a_t> vec;} main_t;int main(){    main_t *test = new main_t;    a_t* parent = new a_t;    b_t* member = new b_t;    member->num = 3;    parent->b_p = member;    test->vec.push_back(*parent);    cout << test->vec.at(0).b_p->num << endl;}
"In order to understand recursion, you must first understand recursion."
My website dedicated to sorting algorithms
It is perfectly fine to use 'struct' in C++, but the 'typedef struct' idiom is useless in C++. C++ does not put struct names in their own namespace, so you never have to write 'struct X' when declaring an instance of the X struct (even without typedef magic). Also, using 'main' as a name for anything besides the main() function is sketchy. :)

As iMalc noted, vectors do not require any special initialization with .clear() or anything else; in C++, objects are supposed to be usable from the get-go - that's what constructors are for - and clean up their own messes - that's what destructors are for. Here, .clear() would fix your bug, but it would miss the point entirely: the whole point of using .push_back to add things to a vector is that you don't need to pre-allocate the space. And the constructor for vector that accepts an element-count pre-loads the vector with default-constructed instances; it doesn't simply allocate space.

And yeah, there's no point to using dynamic allocation for the vector instance itself. In the test code, there isn't even a reason to allocate the 'b' instance dynamically; it's perfectly possible for the 'a' instance to store a pointer to a stack-allocated 'b'. (However, you really, really want to think more about what you're doing here; don't just cram raw pointers into structures without a detailed understanding of what the "ownership policy" will be.)

Basically: you should never, in your first pass of the code, even think about "allocating" anything when you use a vector. :)

#include <iostream>#include <vector>struct b_t {  int num;}; // you do unfortunately still need this semicolon...struct a_t {  b_t* b_p; // C++ style normally puts the pointer on the type name.};struct m_t {  std::vector<a_t> vec;  // Probably a good idea not to rely on 'using' declarations within struct   // declarations. After all, it'll probably be moved to a header, and headers  // should never use using-declarations because then there is no way for a  // source file which #includes the header to "un-use" the declaration.};int main() {  b_t member = { 3 }; // aggregate initialization works in C++ for certain  // very limited cases, called POD structs. The definition of what is POD  // will expand in C++0x.  a_t parent;  parent.b_p = &member;  m_t test;  test.vec.push_back(parent);  std::cout << test.vec.at(0).b_p->num << std::endl;}
That makes perfect sense, I really needed that, thanks :)
Quote:Original post by nobodynews
Quote:Original post by SiCrane
The ghosts of Gilbert and Sullivan possessing your computer?


I hate when that happens. Stupid undefined behavior.

Implementation-defined, not undefined. The Standard specifies that either NULL is returned, or Gilbert and Sullivan possess your computer.

This topic is closed to new replies.

Advertisement