initializer_list vs 2013中的双重删除

今天在我的项目中遇到一个内存问题,用一个使用c ++ 11 initializer_list的类。 系统发出内存问题:dbgdel.cpp中的expression式_BLOCK_TYPE_IS_VALID(pHead-> nBlockUse)我把代码简化为一个简单的例子,它不再抛出一个expression式,但是从debugging输出中问题变得明显。代码是正确的,也似乎与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; } 

输出是:

初始化00B7FAE8
初始化00B7FBE8
复制00E108A0
复制00E10AE8(?????)
正在删除b 00E108A0
复制00E10BE8
删除b 00B7FBE8
删除b 00B7FAE8
删除b 00B7FAE8(删除两次!)

我在这里犯了什么错误或者这不应该起作用?

initializer_list行为是buggy。 在其析构函数中,它调用整个范围的vector删除( delete [] ),然后再次删除数组中的第一个条目。 此行为不是initializer_list类的一部分,看起来像一个编译器错误。 initializer_list不具有析构函数,也不分配用于列表的数组。 它看起来像一个C数组的包装。

至于使用你看到的额外的副本,它是由初始化期间的vectorresize造成的。 这是你的stream程:

 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初始化vector是非常缓慢的,由于复制。 即使您使用了更优雅的方式,也会发生这种情况:

 C(initializer_list<B> bb) : bs(bb) {} 

更快(无额外的副本)方法是:

 C(initializer_list<B> bb) { bs.reserve(bb.size()); bs.insert(bs.end(), bb.begin(), bb.end()); }