list in class creation problem

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <list>
using namespace std;

class node
{
	float ang, dist;
	node* parent;
	list <node*> kids; // an n-way tree structure

	public : node() {}// constructor , empty function atm
	void sprout_node();
	void extend_dist() { dist = dist + 0.1; };
};

void node::sprout_node()
	{
		node n;
		n.parent=this;
		kids.emplace_back(&n);
	}

list <node> root_list; // global list of root nodes

node* add_root()
{
	node n;
	root_list.push_back(n);
	return &n;
}


int main()
{
	node* pn;
	pn=add_root();
	pn->sprout_node();
	return 0;
}


generates a runtime error at pn->sprout_node();
I check with debugger and I note kids list is not created when the node is created. why not?
So I ran some test code

1
2
3
4
5
6
7
8
9
10
11
#include <list>
using namespace std;

class x { list <x*> lx; };


int main()
{
	x n;
	return 0;
}

And here, the list lx IS created. So
1. why is list lx created, but list kids not created?
2. Is the lack of kids list the reason for the runtime exception?

halp plz
Last edited on
1
2
3
4
5
6
node* add_root()
{
	node n;
	root_list.push_back(n);
	return &n;
}


This function returns a pointer to a node, n, that ceases to exist when the function ends, so when you try to use that pointer, you're pointing at memory that doesn't contain a node. Just whatever happens to be in that memory.
Line 19 does the same error; stores a pointer to local variable.
oh. Well that explains a few things. I must have been assuming the compiler would be smart enough to know that : if I'm returning the address of an object, and also sticking the address of the object in a global list, then I still want to keep the object. ( trash collection mentality ? )

So I have to
a.) return the whole object... rather expensive if the object is large, it would be a lot quicker to return just the address.
or
b.) declare the object as global
or
c.) make add_root a method of a class, and n a private of said class

Is any particular way preferential?
The compiler is plenty smart; you misunderstand memory in C and C++. A common affliction, especially amongst those who have come from a Java or similar background.

and also sticking the address of the object in a global list

You're not sticking the address of the object in a global list.

root_list.push_back(n);
This is putting a copy of the object in a global list. Not the address of the object. A copy of it. You could return the address of that copy, since you know that copy will persist:

Something like return &(root_list.back());


You missed:

d) Create the object on the heap so it exists until you delete it, or by using one of the C++11 breed of smart pointers that handle deletion for you

but since you're putting a copy of the object into a global list, you don't need to do that. You can just use that copy, in the global list.


Also:
a.) return the whole object... rather expensive if the object is large, it would be a lot quicker to return just the address.

Probably not expensive, no. The compiler is smart enough to use Return Value Optimisation. Unless you go out of your way to make it difficult, the compiler will recognise the opportunity to avoid a copy and simply return the exact same object that was created, rather than a copy of it; no additional expense.
Last edited on
Dynamic allocation. There is no trash collection, and therefore someone has to manage the deallocation. How about: http://www.cplusplus.com/reference/memory/make_shared/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <list>
#include <memory>
#include <iostream>

using intlist = std::list<std::shared_ptr<int>>;

intlist::value_type add_root( intlist & roots )
{
	roots.push_back( std::make_shared<int>( 42 ) );
	return roots.back();
}

int main()
{
	intlist root_list;
	auto pn = add_root( root_list );
	std::cout << *pn << '\n';
	return 0;
}

You naturally have nodes rather than ints.
Registered users can post here. Sign in or register to post.