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

C++ std::vector back()的奇怪行为,c++,c++11,stdvector,C++,C++11,Stdvector,以下代码在指定位置断言“迭代器+偏移量超出范围。” Input是Layer的一个公共子类。层被声明为 std::vector<Layer *>layers; std::矢量层; 如果我尝试使用更普通的模板类型(例如int*)复制上述内容,则back()可以按预期工作,而不需要断言。不知何故,模板类型在这里很重要。(注意:_ITERATOR_DEBUG_LEVEL为2,它触发vector类中的断言检查。) 我不想直截了当地将代码中的所有back()都更改为size()-1,而是想了

以下代码在指定位置断言“迭代器+偏移量超出范围。”

Input是Layer的一个公共子类。层被声明为

std::vector<Layer *>layers;
std::矢量层;
如果我尝试使用更普通的模板类型(例如int*)复制上述内容,则back()可以按预期工作,而不需要断言。不知何故,模板类型在这里很重要。(注意:_ITERATOR_DEBUG_LEVEL为2,它触发vector类中的断言检查。)

我不想直截了当地将代码中的所有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);
}
#包括
使用名称空间std;
名称空间层{
类层{
公众:
层(浮动α=0,浮动动量=0.9f,浮动重量衰减=0);
虚拟层();
//所有层都应具有的三个虚拟方法
虚空前进(布尔列=真)=0;
虚空向后()=0;
虚拟void update()=0;
void adjust_learning(浮动刻度);//更改学习速率
Layer*prev;//上一层
层*下一层;//下一层
float*data;//X”:输出(cuDNN y)
int batch;//n:批大小
float alpha;//学习速率
浮点动量;//β:梯度动量
浮动重量衰减;//伽马:重量衰减率
};
}/*命名空间层*/
名称空间层{
图层::图层(浮动alpha、浮动动量、浮动权重衰减)
{
std::memset(this,0,sizeof(*this));
阿尔法=阿尔法;
动量=动量;
重量衰减=重量衰减;
}
图层::~Layer(){}
空层::调整_学习(浮动比例){
α*=标度;
}
}
名称空间层{
类输入:公共层{
公众:
输入(整数n、整数c、整数h、整数w、浮点*_数据);
虚拟输入();
无效前进(布尔列=真);
向后作废();
无效更新();
};
}
名称空间层{
Input::Input(intn,intc,inth,intw,float*_数据):Layer(){
prev=NULL;
批次=n;
数据=_数据;
}
输入::~Input(){
数据=空;
}
无效输入::前进(布尔列车){
//没什么
}
void输入::backward(){
//没什么
}
无效输入::更新(){
//没什么
}
}
使用名称空间层;
名称空间模型{
班级网络{
私人:
std::vector layers;//层列表
bool有\u输入,有\u输出;//健全性检查
float*data;//设备上的输入
int batch;//数据的整个大小,批大小
公众:
网络(int批量大小);
虚拟网络();
无效输入(int c、int h、int w);
};
}
名称空间模型{
void网络::PushInput(int c、int h、int w){
输入*输入=新输入(批次、c、h、w、数据);
层。推回(输入);
Layer*foo=layers.back();//**为什么要断言**
}
网络::网络(整数批处理){
std::memset(this,0,sizeof(*this));
批次=_批次;
}
网络::~Network(){
用于(层*l:层)
删除l;
}
}
void main()
{
模型:网络foo(10);
foo.PushInput(2,3,4);
}
您的代码中有未定义的行为

构造函数中

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

这样做的问题是,上面的调用也将清除虚拟函数表(它是对象的一部分)。在此之后调用的任何虚拟函数都不会像预期的那样工作。这包括销毁对象,因为析构函数是虚拟的。

此处断言是什么意思?实际诊断是什么?是否有stacktrace?如图所示,代码应该可以正常工作。在
push_back
back
调用之间是否发生了一些您没有向我们展示的事情?请尝试创建一个并向我们展示它。我为第一行中的断言消息增加了勇气。
int*
Layer*
相比并不普通,指针只是指针,不管它们指向的东西有多特殊。@Pileborg:没有其他事情发生。在push_back()之后立即调用back()会触发断言。我将开始减去代码,并查找是什么停止了断言。实际上,网络类中的memset是问题的根源!注释这一点可以修复断言。不过,你的评论修复了我代码中的一个单独错误!谢谢@WaltDonovan哦,我错过了那个,但是是的,这也会引起问题,因为它会使
向量
成员全部。。。“奇怪”。)这里的教训是什么?不要在C++对象上使用C函数。显式初始化(最好是在构造函数初始值设定项列表中)是一种方法。
std::memset(this, 0, sizeof(*this));