[英]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.