1

私は、指定された指示に従って大学の問題を解決しようとしました。コードはコンパイルされますが、メモリに関する警告が生成されます。 ()基本的には自動テストからのコードですC++ shared_ptrの継承メモリの問題「不正な割り当て解除」

#include <iostream> 
#include <vector> 
#include <memory>  
using std::vector; 
using std::shared_ptr; 
using std::make_shared; 

class ApsClass { 
    protected : 
     double goose; 

    public : 
     virtual ~ApsClass() {} 
     virtual shared_ptr<ApsClass> clone() const = 0; 
     double GetGoose() const { return goose; } 
}; 


class DerivedClass : public ApsClass { 
    public : 
     ~DerivedClass() {} // Warning here* 
     DerivedClass(double goose) { DerivedClass::goose = goose; } 
     shared_ptr<ApsClass> clone() const override; 
}; 

shared_ptr<ApsClass> DerivedClass::clone() const { 
    return make_shared<DerivedClass>(goose); 
} 

class Storage { 
    vector<shared_ptr<ApsClass>> geese; 

    public : 
     Storage() {} 
     ApsClass *AddApsClass(ApsClass *pok); 
     void DelApsClass(ApsClass *pok); 
}; 

ApsClass *Storage::AddApsClass(ApsClass *pok) 
{ 
    // The instructions stated that the object pointed at by pok has no 
    // other pointers pointing at it, and should now be "owned" by geese 
    geese.push_back(shared_ptr<ApsClass>(pok)); 
    return pok; 
} 

void Storage::DelApsClass(ApsClass *pok) 
{ 
    for (int i = 0; i < geese.size(); i++) 
     if (geese[i] == shared_ptr<ApsClass>(pok)) { 
      geese.erase(geese.begin() + i); 
      break; 
     } 
} 

int main() 
{ 
    Storage Foo; 
    ApsClass *s = Foo.AddApsClass(new DerivedClass(0.5)); 
    Foo.DelApsClass(s); 
    return 0; 
} 

メイン、私は()メインが正常に動作するようにプログラムの残りの部分を修正することになっています。ここでは、コードの核心です。
警告は派生クラス*のデストラクタ定義で報告され、英語に翻訳されたときには "Bad deallocation"と表示されます。私の質問です:どこで、なぜこの問題はコード内に発生しますか?

私が切り出したコードは、メモリ割り当てには何の影響もありません(私が願っています)、私はあまりアクセスできないオートテストによってテストされています。一つの試験は、とりわけ次のように報告されます

Invalid read of size 8 ... 
Address 0x51f0090 is 0 bytes inside a block of size 56 free'd 

==10216== Jump to the invalid address stated on the next line 
==10216== at 0x0: ??? 
Address 0x0 is not stack'd, malloc'd or (recently) free'd 

==10216== Process terminating with default action of signal 11 (SIGSEGV) 
==10216== Bad permissions for mapped region at address 0x0 
==10216== at 0x0: ??? 

詳細については、私はここに元のコードのいくつかを置くことができる必要がある場合。

答えて

6

shared_ptr<ApsClass>(pok)を実行するたびに、他のすべてのshared_ptrが同じオブジェクトを指していることを知らない新しいshared_ptrが作成されます。したがって、このshared_ptrが破壊されると、オブジェクトが破壊されます。

しかし、何回か(あなたのケースでは2回)、オブジェクトが複数回破壊されるためです。

通常ポインタから作成されたshared_ptrのみがこの問題を抱えています。別のshared_ptrからshared_ptrを作成するのは問題ありません。

shared_ptr<ApsClass> aps(new DerivedClass(0.5)); 
shared_ptr<ApsClass> s = Foo.AddApsClass(aps); 
Foo.DelApsClass(s); 

ApsClass *shared_ptr<ApsClass>から他のどこでも変更:このこの

ApsClass *s = Foo.AddApsClass(new DerivedClass(0.5)); 
Foo.DelApsClass(s); 

を変更 -

あなたはshared_ptr一度に作成する必要があります。

+3

私はそれです。未処理のポインタが 'shared_ptr'によって管理されると、未処理のポインタはもはや使用されなくなります(ただし、レガシーコードとのインタフェース以外は' shared_ptr :: get() 'を使用します)。代わりに 'shared_ptr'(あるいは循環参照を防ぐ必要がある場合は' weak_ptr')だけを渡して、そのような問題を回避してください。 – zett42

+0

私は参照してください。しかし、問題は今main()のコードが自動テストの(変更された)コードであることです(私は質問にこれをETAします)。私はここでメイン()を変更することは許されていません。 – sishke

+1

@sishkeそれから、 'DelapsClass'が' shared_ptr'を作成しないように、少なくとも 'geese [i] == shared_ptr (pok)'を '' geese [i] .get()== pok'に変更してください。 。 – immibis

関連する問題