在initializer_list与2013中双删除 [英] Double delete in initializer_list vs 2013

查看:120
本文介绍了在initializer_list与2013中双删除的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

今天在我的项目中遇到一个内存问题,用一个类使用c ++ 11 initializer_list。系统发出一个内存问题:dbgdel.cpp中的表达式_BLOCK_TYPE_IS_VALID(pHead-> nBlockUse)。我将代码简化为一个简单的例子,它不再抛出一个表达式,但问题从调试输出中显而易见在我的眼中代码是正确的,它似乎也与g ++一起工作。

Today in run into a memory problem in my project, with a class using c++ 11 initializer_list. The system signals a memory problem: "Expression _BLOCK_TYPE_IS_VALID(pHead->nBlockUse) in dbgdel.cpp. I simplified the code to a simple example, it no longer throws an expression but the problem becomes apparent from the debug output. In my eyes this code is correct, also it seems to work with 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!)

我在这里或者这不应该工作?

What mistake I make here or is this not supposed to work?

推荐答案

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

The initializer_list behavior is buggy. In its destructor it calls a vector delete (a delete[]) of the entire range and then deletes the first entry in the array again. This behavior is not part of the initializer_list class and looks like a compiler bug. initializer_list doesn't have a destructor and doesn't allocate the array used for the list. It just looks like a wrapper for a C array.

对于使用额外的副本,你看到,它是由矢量调整大小从它的初始化。
这是你的流程:

As for using the extra copy you see, it's caused by the vector resizing from during its initialization. Here's your flow:

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初始化一个向量是相当慢由于复制。即使你使用了更优雅的方式也会发生这种情况:

What you can see here is the initializing a vector via push_back is quite slow due to copying. This would be happen even if you've used the more elegant way:

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

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

A faster (no extra copies) method is:

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

这篇关于在initializer_list与2013中双删除的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆