2011-09-27 29 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對動態分配的回答。但是如果你想要一種不需要參考計數的方法等,那麼你可以這樣做......