2016-05-06 7 views
-2

次のコードは、の "iterator + offset is not range"と表示された場所にアサートします。std :: vectorの奇妙な動作back()

void Network::PushInput(int c, int h, int w) { 
    Input* input = new Input(batch, c, h, w, data); 
    layers.push_back(input); // this happens to be the first push_back() 
// layers.push_back(input); // doing another doesn't change the assert! 
    Layer *foo = layers.back(); // asserts here 
    Layer *baz = layers[layers.size()-1]; // does not assert 
} 

入力はLayerのパブリックサブクラスです。層は、私は、例えば、int型*、より多くのバニラテンプレートタイプで上記を複製しようとした場合)(バック、

std::vector<Layer *>layers; 

として宣言されていないと主張する期待どおりに動作されます。どういうわけか、テンプレートタイプがここで重要です。 (注:_ITERATOR_DEBUG_LEVELは2で、これはベクトルクラスのアサーションチェックをトリガーします)

コード内のback()のすべてをsize() - 1に変更するのではなくむしろここで何が起こっているのか理解する。

アイデア? (私はこの問題の原因を突き止めるまでコードを混乱させるでしょうが、うまくいけば他の人には分かります)

(私はVisual Studio 2013 Community Editionを使用しています)

#include <vector> 

using namespace std; 

namespace layer { 
    class Layer { 
    public: 
     Layer(float alpha = 0, float momentum = 0.9f, float weight_decay = 0); 
     virtual ~Layer(); 

     // three virtual method that all layers should have 
     virtual void forward(bool train = true) = 0; 
     virtual void backward() = 0; 
     virtual void update() = 0; 

     void adjust_learning(float scale); // change the learning rate 

     Layer* prev;     // previous layer 
     Layer* next;     // next layer 
     float* data;     // X': output (cuDNN y) 
     int batch;      // n: batch size 
     float alpha;     // learning rate 
     float momentum;     // beta: momentum of gradient 
     float weight_decay;    // gamma: weight decay rate 
    }; 
} /* namespace layer */ 

namespace layer { 
    Layer::Layer(float alpha_, float momentum_, float weight_decay_) 
    { 
     std::memset(this, 0, sizeof(*this)); 
     alpha = alpha_; 
     momentum = momentum_; 
     weight_decay = weight_decay_; 
    } 

    Layer::~Layer() {} 

    void Layer::adjust_learning(float scale) { 
     alpha *= scale; 
    } 
} 

namespace layer { 

    class Input : public Layer { 
    public: 
     Input(int n, int c, int h, int w, float* _data); 
     virtual ~Input(); 
     void forward(bool train = true); 
     void backward(); 
     void update(); 
    }; 

} 

namespace layer { 

    Input::Input(int n, int c, int h, int w, float* _data) : Layer() { 
     prev = NULL; 

     batch = n; 
     data = _data; 
    } 

    Input::~Input() { 
     data = NULL; 
    } 

    void Input::forward(bool train) { 
     // nothing 
    } 

    void Input::backward() { 
     // nothing 
    } 

    void Input::update() { 
     // nothing 
    } 

} 

using namespace layer; 

namespace model { 

    class Network { 
    private: 
     std::vector<Layer*> layers; // list of layers 
     bool has_input, has_output; // sanity check 
     float* data; // input on device 
     int batch; // whole size of data, batch size 
    public: 
     Network(int batch_size); 
     virtual ~Network(); 
     void PushInput(int c, int h, int w); 
    }; 
} 

namespace model { 
    void Network::PushInput(int c, int h, int w) { 

     Input* input = new Input(batch, c, h, w, data); 
     layers.push_back(input); 
     Layer *foo = layers.back(); // **WHY DOES THIS ASSERT??** 
    } 
    Network::Network(int _batch) { 
     std::memset(this, 0, sizeof(*this)); 
     batch = _batch; 
    } 

    Network::~Network() { 
     for (Layer* l : layers) 
      delete l; 
    } 
} 

void main() 
{ 
    model::Network foo(10); 

    foo.PushInput(2, 3, 4); 
} 
+2

「ここにアサートする」とはどういう意味ですか?実際の診断とは何ですか?スタックトレースはありますか? –

+0

このコードは、うまくいくはずです。 'push_back'と' back'呼び出しの間に何か起こっていることはありますか? [最小限の、完全で検証可能な例](http://stackoverflow.com/help/mcve)を作成してください。 –

+0

私は最初の行にあるアサーションメッセージを強調しました。 –

答えて

4

あなたは、あなたのコード内で未定義の動作を持っている:

.....

は、ここでそれが問題を示してコンパイルし、スタンドアロンのファイルです。

あなたは

std::memset(this, 0, sizeof(*this)); 

を行うLayerコンストラクタでは、これに伴う問題は、上記の呼び出しは、同様に(オブジェクトの一部である)仮想関数テーブルをクリアすることです。それ以降に呼び出される仮想関数は、まったく期待通りに機能しません。これには、デストラクタが仮想であるときのオブジェクトの破壊も含まれます。

+0

実際には、問題の原因となっているNetworkクラスのmemsetです。それがアサルトを修正するとコメントします。あなたのコメントは私のコードの別のバグを修正します!ありがとう!! –

+2

@WaltDonovanああ、私はそれを逃しましたが、それは問題を引き起こすでしょう、それは 'ベクトル'メンバーをすべて... "奇妙な"ものにするでしょう。 :)ここのレッスンは? C++オブジェクトでC関数を使用しないでください。 :)明示的な初期化(好ましくはコンストラクタの初期化子リスト内で)は、行く方法です。 –