2016-11-16 27 views
0

我有一個類動物是幾個不同的動物的基類和一個類牧羣存儲shared_prt動物的向量。我不熟悉智能指針,但是我不得不在我的代碼中使用它們來處理繼承。它似乎工作正常,但在我的代碼到達「Herd」的析構函數後,它拋出一個error。 它有什麼問題?類的矢量的shared_ptr的類的析構函數導致錯誤

class Animal { 
public: 
    Animal(string _sound) : 
     sound(_sound) {} 
    void give_sound() { 
     cout << sound << " "; 
    } 
    bool operator==(Animal arg) { 
     return (typeid(*this).name() == typeid(arg).name()); 
    } 
protected: 
    string sound; 
}; 

class Dog : public Animal { 
public: 
    Dog() : Animal("woof") {} 
}; 

class Cat : public Animal { 
public: 
    Cat() : Animal("meow") {} 
}; 

class Cow : public Animal { 
public: 
    Cow() : Animal("moo") {} 
}; 

class Herd { 
public: 
    Herd() {} 
    ~Herd() { 
     vec.clear(); 
    } 

    Herd operator+(Animal *arg) { 
     shared_ptr<Animal> ptr(arg); 
     vec.push_back(ptr); 
     return *this; 
    } 

    void operator+=(Animal *arg) { 
     shared_ptr<Animal> ptr(arg); 
     vec.push_back(ptr); 
    } 


    void make_noise() { 
     vector<shared_ptr<Animal>>::iterator v = vec.begin(); 
     while (v != vec.end()) { 
      (*v)->give_sound(); 
      v++; 
     } 
     cout << endl; 
    } 

private: 
    vector<shared_ptr<Animal>> vec; 
}; 

int main() { 
    Herd herd; 
    Dog d1, d2; 
    Cat c1, c2; 
    cout << "sound 1: " << endl; 
    herd.make_noise(); 
    herd += &d1; 
    herd += &c1; 
    cout << "sound 2: " << endl; 
    herd.make_noise(); 
    herd += &d2; 
    herd += &c2; 
    cout << "sound 3: " << endl; 
    herd.make_noise(); 
    //herd = herd - &d1; 
    //herd = herd - &d2; 
    cout << "sound 4: " << endl; 
    herd.make_noise(); 
    return 0; 
} 

edit:without vec.clear()它也崩潰。

+0

在問題中發佈代碼。 – molbdnilo

+0

@molbdnilo這裏是 – IFeel3

+0

「*我不熟悉智能指針,但我不得不在我的代碼中使用它們來處理繼承。*」我有點困惑。由於對象是分配在堆棧上的,因此智能指針在這裏顯然不起作用。但是一個普通的啞指針應該工作得很好。爲什麼你認爲你需要智能指針? –

回答

2
Dog d1, d2; 
Cat c1, c2; 

這些對象具有自動存儲持續時間。它們並不意味着被擁有智能指針來管理。

的應用案例智能指針是堆分配,例如:

herd += new Dog; 
+0

那我應該怎麼申報呢? – IFeel3

+0

@ IFeel3,你不需要。 'std :: make_shared'創建一個具有動態存儲持續時間的對象,並立即將其交給一個智能指針。你不需要聲明'd1,d2,c1,c2' – StoryTeller

+0

是不是宣佈動物對象像'狗* d =新狗;'優先? – IFeel3

1

您的問題是通過變量的地址與自動存儲時間。 請參閱:Stack, Static, and Heap in C++

這是你的代碼會發生什麼:

您有自動存儲時間創建一個變量:

Dog d1 

它會走出去的範圍後自動銷燬(在你的案例結束的主要功能)

然後,您將它的地址傳遞給一個將此地址存儲在SharedPtr中的函數:

Herd operator+(Animal *arg) { 
    shared_ptr<Animal> ptr(arg); 
    vec.push_back(ptr); 
    return *this; 
} 

這樣做你告訴shared_ptr它負責刪除這個對象。 (簡單地說,共享指針的析構函數將調用delete Animal

因此,您的對象將被釋放兩次,這是禁止的。

而不是使用原始指針,你應該使用:

operator+(shared_ptr<Animal> arg) 

,並分配你的對象在以下方式:

std::shared_ptr<Dog> d1 = std::make_shared<Dog>(); 
1

這有什麼錯呢?

在此代碼中,您嘗試使用堆棧分配對象創建shared_ptr。這會導致此對象的雙重刪除,第一個會在堆棧對象超出範圍時發生。第二個發生在delete運營商的shared_ptr析構函數中。第二個是無效的,程序崩潰。

Herd operator+(Animal *arg) { 
    shared_ptr<Animal> ptr(arg); 
    vec.push_back(ptr); 
    return *this; 
} 

void operator+=(Animal *arg) { 
    shared_ptr<Animal> ptr(arg); 
    vec.push_back(ptr); 
} 
+0

更精確地說,錯誤發生在* first *刪除處。標準全局分配器無法找到其元數據時。第一個析構函數調用不是由於'delete'而是自動的。 – StoryTeller

+1

是的,錯誤發生在'delete'操作符第一次刪除堆棧分配對象時。 – ks1322

0

我可以看到兩個明顯的問題。

首先,正如其他人所說,是shared_ptr假定它管理是動態創建的對象(與運營商new),所以使用運算delete(除非構建shared_ptr當提供定製刪除的版本中,你的代碼沒有按「做T應用delete運算符將物體與auto儲存期限會導致不確定的行爲

第二個問題 - 。您將修復後的第一個最終遭遇 - 被該類Animal沒有virtual析構函數即使對象是使用運算符new創建的,運算符delete將導致從Animal派生的實際類型對象的未定義行爲(即,如果實際對象的類型爲Cat,Dog等)。

相關問題