It looks like you are creating a data structure here where children have pointers to their parents. Using temporaries is guaranteed to cause you grief in this case. In order to make this safe, you will need to dynamically allocate and possibly use some sort of reference counting.
Have you considered using boost::shared_ptr
? It is an implementation of a reference counted smart pointer class. Using shared_ptr
and perhaps some factory methods, you might be able to get the effect you want and reduce the pain of dynamic memory allocation. I tried it out and it seems to work. Once the code exits the scope, the objects are all destroyed because there are no references left to the shared_ptrs.
Edit:
In response to zounds' comment, I have modified the example so that the root object controls the data structure's lifetime.
#include <iostream>
#include <string>
#include <vector>
#include <boost\shared_ptr.hpp>
#include <boost\weak_ptr.hpp>
using boost::shared_ptr;
using boost::weak_ptr;
using std::string;
using std::cout;
using std::endl;
using std::vector;
class person;
typedef shared_ptr<person> Person;
typedef weak_ptr<person> PersonWk;
class person {
PersonWk pThis;
friend Person makePerson(const string & nam, Person m = Person());
string name;
PersonWk mommy; // children should not affect parent lifetime, so store weak ptr
vector<Person> children; // parents affect children lifetime so store child shared ptrs
// make constructor private so that you can only make a person using factory method
person(const string & nam, Person m) : name(nam), mommy(m)
{
// for demo purposes
printf("creating %s\n", nam.c_str());
++personCount;
}
// undefined copy constructor and assignment operators
person(const person&);
person& operator=(const person&);
public:
// for demo purposes
static int personCount;
~person()
{
// for demo purposes
printf("destroying %s\n", name.c_str());
--personCount;
}
Person baby(const string & nam){
Person child = makePerson(nam, Person(pThis));
children.push_back(child);
return child;
}
void talk() const{
if (Person mom = mommy.lock())
mom->talk();
cout << name << endl;
}
};
int person::personCount = 0;
// factory method to make a person
Person makePerson(const string & name, Person m) {
Person p = Person(new person(name, m));
p->pThis = p; // stash weak_ptr so I can use it to make a shared_ptr from "this" in the baby method
return p;
}
void use(const Person p) {
printf("In method use...\n");
p->talk();
}
int _tmain(int argc, _TCHAR* argv[])
{
printf("personCount=%d\n", person::personCount);
{
Person ann = makePerson("Ann");
// ann has baby and grandbaby, pass grandbaby to use method
use(ann->baby("Susan")->baby("Wendy"));
ann.reset(); // remove reference from root object. Destruction ensues...
}
printf("personCount=%d\n", person::personCount);
return 0;
}
const int &i = std::vector<int>(1)[0];
is "not fine".vector
doesn't stop you writing that, and doesn't need to. The key here is that because destroying the mommy renders the baby unusable, the baby is part of the mommy. That's what's wrong with the design, it's counter-intuitive. You're trying to patch that up by preventing there being any such thing as an orphan, which might be appropriate but you should also consider whether orphans should just have better defined behavior, or should be more obviously a bad thing to create. – Itin