簡體   English   中英

std::vector back() 的奇怪行為

[英]Odd behavior of 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
}

Input 是 Layer 的公共子類。 層被聲明為

std::vector<Layer *>layers;

如果我嘗試使用更多的 vanilla 模板類型復制上述內容,例如 int*,back() 將按預期工作,沒有斷言。 不知何故,模板類型在這里很重要。 (注意:_ITERATOR_DEBUG_LEVEL 是 2,這會觸發向量類中的斷言檢查。)

我寧願不直截了當地將代碼中的所有 back() 更改為 size()-1,而是希望了解這里發生了什么。

有任何想法嗎? (我將繼續擾亂代碼,直到找到造成這種情況的明顯原因,但希望這對其他人來說是顯而易見的。)

(如果重要的話,我使用的是 Visual Studio 2013 社區版。)

.....

這是一個編譯后顯示問題的獨立文件:

#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);
}

您的代碼中有未定義的行為

Layer構造函數中,您執行

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

這樣做的問題是上面的調用也會清除虛函數表(它是對象的一部分)。 之后調用的任何虛函數都不會按預期工作,如果有的話。 這包括對象的銷毀,因為析構函數是虛擬的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM