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

时间:2016-05-06 21:58:29

标签: c++ c++11 stdvector

以下代码在指示的地方断言"迭代器+偏移量超出范围。"

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

1 个答案:

答案 0 :(得分:4)

您的代码中有未定义的行为

Layer构造函数中执行

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

这个问题是上面的调用也会清除虚函数表(它是对象的一部分)。之后调用的任何虚函数都将无法正常工作(如果有的话)。这包括破坏对象,因为析构函数是虚拟的。