今天遇到了我的项目中的内存问题,使用了一个使用c ++ 11 initializer_list的类。系统发出内存问题:dbgdel.cpp中的表达式_BLOCK_TYPE_IS_VALID(pHead-> nBlockUse)。我将代码简化为一个简单的示例,它不再抛出表达式,但问题从调试输出中变得明显。在我看来这段代码是正确的,它似乎也适用于g ++。
#include <functional>
#include <memory>
#include <string>
#include <iostream>
#include <vector>
#include <map>
#include <sstream>
#include <initializer_list>
using namespace std;
class B {
public:
char data[256];
B(const string& x) {
cout << "Init " << this << endl;
}
B(const B& b) {
cout << "Copy " << this << endl;
}
~B() {
cout << "Deleting b " << this << endl;
}
};
class C {
public:
vector<B> bs;
C(initializer_list<B> bb) {
for(auto& b : bb) {
bs.push_back(b);
}
}
};
int main(int argc, char** argv) {
C bb { B("foo"), B("bar") };
return 0;
}
输出结果为:
Init 00B7FAE8 Init 00B7FBE8 Copy 00E108A0 Copy 00E10AE8 (?????) Deleting b 00E108A0 Copy 00E10BE8 Deleting b 00B7FBE8 Deleting b 00B7FAE8 Deleting b 00B7FAE8 (Deleted twice!)
我在这里犯了什么错误,或者这不应该起作用?
答案 0 :(得分:11)
initializer_list行为是错误的。在它的析构函数中,它调用整个范围的向量删除( delete [] ),然后再次删除数组中的第一个条目。 此行为不是initializer_list类的一部分,看起来像编译器错误。 initializer_list没有析构函数,也没有分配用于列表的数组。它看起来像是C数组的包装器。
至于使用你看到的额外副本,它是由初始化期间向量调整大小引起的。 这是你的流程:
Init 00B7FAE8 // construct "foo"
Init 00B7FBE8 // construct "bar"
Copy 00E108A0 // copy "foo" to vector (capacity=1)
Copy 00E10AE8 (?????) // copy the above object to the resized vector (capacity = 2)
Deleting b 00E108A0 // delete the smaller vector buffer
Copy 00E10BE8 // copy "bar" from initialization_list to vector
Deleting b 00B7FBE8 // delete initialization_list in reverse order. this is "bar"
Deleting b 00B7FAE8 // last to delete. this is "foo"
Deleting b 00B7FAE8 (bug)
// later C::bs is destroyed
你可以在这里看到的是,由于复制,通过push_back初始化一个向量非常慢。即使您使用了更优雅的方式,也会发生这种情况:
C(initializer_list<B> bb) : bs(bb) {}
更快(无额外副本)的方法是:
C(initializer_list<B> bb) {
bs.reserve(bb.size());
bs.insert(bs.end(), bb.begin(), bb.end());
}