std::vector back() 的奇怪行为
Odd behavior of std::vector back()
以下代码在指定位置断言 "iterator+offset is out of range."
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
}
输入是图层的 public 子class。图层声明为
std::vector<Layer *>layers;
如果我尝试用更多普通模板类型(例如 int*)复制上面的内容,back() 将按预期工作而没有断言。不知何故,模板类型在这里很重要。 (注意:_ITERATOR_DEBUG_LEVEL 为 2,这会触发断言检查向量 class。)
我不想直接将代码中的所有 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));
问题是上面的调用也会清除虚函数table(它是对象的一部分)。之后调用的任何虚函数都不会按预期工作,如果有的话。这包括对象的销毁,因为析构函数是虚拟的。
以下代码在指定位置断言 "iterator+offset is out of range."
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
}
输入是图层的 public 子class。图层声明为
std::vector<Layer *>layers;
如果我尝试用更多普通模板类型(例如 int*)复制上面的内容,back() 将按预期工作而没有断言。不知何故,模板类型在这里很重要。 (注意:_ITERATOR_DEBUG_LEVEL 为 2,这会触发断言检查向量 class。)
我不想直接将代码中的所有 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));
问题是上面的调用也会清除虚函数table(它是对象的一部分)。之后调用的任何虚函数都不会按预期工作,如果有的话。这包括对象的销毁,因为析构函数是虚拟的。