2011-09-27 79 views
8

这可能是不可能的,但我想知道是否有可能通过它的原始表达来保持暂时的永久。我有一个指向父对象对象链,这将创建一个子对象的成员函数,一个简单的例子是在这里防止暂时延长其寿命?

class person{ 
    string name; 
    person * mommy; 
public: 
    person(const string & nam, person * m = 0) : name(nam), mommy(m) {} 
    person baby(const string & nam){ 
     return person(nam, this); 
    } 
    void talk() const{ 
     if (mommy) mommy->talk(); 
     cout << name << endl; 
    } 
}; 

int main(){ 
    person("Ann").baby("Susan").baby("Wendy").talk();  // fine 

    const person & babygirl = person("Julie").baby("Laura"); // not fine 

    babygirl.talk(); // segfault 
    return 0; 
} 

我想用person是将其传递给函数的方式,和这样的事情:

void use(const person & p) { 
    p.talk(); 
} 
use(person("Anna").baby("Lisa")); 

很好。

只要没有一个临时存活通过原始表达式,但是如果我将其中一个临时临时对象绑定到一个常量引用,它的父项就不能存活,并且我得到一个段错误。我可以隐藏person的拷贝构造函数和赋值操作符,但有什么办法可以防止这种错误发生?如果可能,我想避免动态分配。

+0

@Konrad:Ironic; - ] – ildjarn

+1

请注意,这段代码是“不好”的相同方式写'const int&i = std :: vector (1)[0];'是“不好”。 'vector'不会阻止你写这个,也不需要。这里的关键是,因为摧毁妈妈使宝宝无法使用,宝宝是妈妈的一部分。这就是设计的问题,这是违反直觉的。你试图通过阻止孤儿这样的事情来补救,这可能是合适的,但你也应该考虑孤儿是否应该有更好的定义行为,或者应该更明显是一个坏的事情来创建。 –

+0

同意史蒂夫:这只是糟糕的设计展示。裸指针的外观应该已经给出了某种东西没有。 –

回答

3

看起来你正在创建一个数据结构,在这里孩子们有指向父母的指针。在这种情况下,使用临时工会保证让你感到悲伤。为了安全起见,您需要动态分配并可能使用某种引用计数。

您是否考虑过使用boost::shared_ptr?它是引用计数智能指针类的实现。使用shared_ptr以及可能的某些工厂方法,您可能能够获得所需的效果并减少动态内存分配的麻烦。我试了一下,它似乎工作。一旦代码退出范围,对象将被全部销毁,因为没有引用留给shared_ptrs。

编辑: 响应于zounds'评论,我已修改的示例,以使根对象控制的数据结构的寿命。

#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; 
} 
+0

感谢您的回答。共享ptr的问题在于,根对象可能需要具有特定的销毁点,我不想担心它可能存在某处存储的指针。我只需要临时存在,只要一个函数调用就可以死掉。我正在使用儿童 - >父母结构,孩子不允许影响他们的父母(除非通过每个人都可以使用的普通公共接口) – zounds

+0

一种方法可以是将根对象存储在已知位置。然后让每个家长保持shared_ptrs给他们的孩子,孩子们可以保持weak_ptrs给他们的父母。然后,当您将根对象设置为NULL(从而移除所有引用)时,树会从顶部到底部销毁。 –

+0

修改后的代码示例在我之前的评论中使用该方法。 –

0

你必须做这样的事情:

void use(const person & p) { 
    p.talk(); 
} 
person a("Anna"); 
use(a.baby("Lisa")); 

这样,父“一个”不出去的范围,直到你真正用它做(后呼叫“使用”)。

原始代码的问题在于,父母“Anna”只需保持足够长的时间来调用“宝贝”,并且在进行函数调用之前父母可以被丢弃。通过使父变量具有作用域,您可以控制何时被破坏。

这看起来对我来说很危险吗?是。因此,我建议看看m-sharp对动态分配的回答。但是如果你想要一种不需要参考计数的方法等,那么你可以这样做......