当我push_back到向量时调用析构函数

Ale*_*hul 2 c++ destructor vector

我有这个类定义:

class FlashStream
{
public:
    explicit FlashStream(const char * url, vector<uint8> * headers, vector<uint8> * data, void * ndata, void * notifyData = NULL, uint32 lastModified = NULL);
    ~FlashStream();
private:        
    NPStream      _stream;
    // ...
}
Run Code Online (Sandbox Code Playgroud)

(NPStream描述)

及其实施:

FlashStream::FlashStream(const char * url, vector<uint8> * headers, vector<uint8> * data, void * ndata, void * notifyData, uint32 lastModified)
{
    // ...
    memset(&_stream, 0, sizeof(NPStream));

    _stream.headers = new char[data->size()]; 

    memcpy((void*)_stream.headers, &(*data)[0], data->size());
    // ...
}

FlashStream::~FlashStream()
{
    // ...
    if(_stream.headers)
        delete [] _stream.headers;
    _stream.headers = NULL;
    // ...
}
Run Code Online (Sandbox Code Playgroud)

现在,当我运行此代码时:

// ...
vector<FlashStream> _streams;
// ...
_streams.push_back(FlashStream(url, headers, data, _npp.ndata, notifyData, lastModified));
// ...
Run Code Online (Sandbox Code Playgroud)

有时候我delete [] _stream.headers;在析构函数中有一个错误,FlashStream当我push_back()去的时候会调用它vector<FlashStream> _streams.

在SO和其他几个问题上阅读了这个问题,但所有相同的人都不知道如何优雅有效地解决问题.可问题是在拷贝构造函数,但我不知道我怎么能与内存分配,使其成为NPStream.headersNPStream.url

iva*_*ult 6

析构函数 atpush_back()可以在两种情况下调用。

  • 如前所述,第一种情况发生在将临时对象推入向量时。这不是最好的主意,因为将调用构造函数、复制构造函数和析构函数。您可以将指向对象的指针存储在向量中以避免冗余调用。

    C++11 附带的新功能可能会对您有所帮助。

    • 为了避免不必要的复制,请使用std::vector::emplace_back(). 它在向量中就地构造一个对象,而不是复制。

    • 此外,您还可以使用 的移动版本push_back(value_type&& val)。只需在类中定义一个移动构造函数,移动版本push_back()就会自动对临时对象起作用。

  • 第二种情况是达到向量的容量。向量有两个主要值:大小和容量。大小是向量中当前保存的元素数量。容量是向量存储可以容纳的元素数量。因此,当您推回一个元素时,您就增加了向量的大小。如果容量不足以容纳新元素,向量将执行重新分配以增加其容量。在重新分配期间,向量使用复制/移动构造函数重新构造其对象,并使用析构函数删除旧对象。因此,在 处push_back(),向量可以多次调用对象的析构函数。

要降低向量重新调整大小的成本push_back(),请始终使用该std::vector::reserve()方法为对象预分配存储:

std::vector<int> vec;
vec.reserve(20);
for(int i = 0; i<20; ++i)
    vec.push_back(i)
Run Code Online (Sandbox Code Playgroud)

此外,您可以通过定义移动构造函数来降低复制对象的成本:

class C
{
public:
    C(int c)
        : m_c(c)
    {
        std::cout << "C(int c)" << std::endl;
    }
    C(C&& c)
        : m_c(c.m_c)
    {
        std::cout << "C(C&& c)" << std::endl;
    }
    C(const C& c)
        : m_c(c.m_c)
    {
        std::cout << "C(const C& c)" << std::endl;
    }
    ~C()
    {
        std::cout << "~C()" << std::endl;
    }
private:
    int m_c;
};

int main()
{
    std::vector<C> vc;
    for (int i = 0; i < 100; ++i)
        vc.push_back(C(i));
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

如果你编译并运行它,你会发现它C(const C& c)根本没有被调用。由于定义了移动构造函数,push_back()因此重新分配将移动您的对象而不是复制它们。


Mar*_* J. 5

这个说法:

_streams.push_back(FlashStream(url, headers, data, _npp.ndata, notifyData, lastModified));
Run Code Online (Sandbox Code Playgroud)

相当于:

{
    FlashStream temp(url, headers, data, _npp.ndata, notifyData, lastModified);
    _streams.push_back(temp);
    // temp gets destroyed here
}
Run Code Online (Sandbox Code Playgroud)

因此,您创建一个临时的FlashStream对象,该对象被复制到向量中,然后被破坏.您可以通过emplace_back()在C++ 11中使用来避免这种情况:

_streams.emplace_back(url, headers, data, _npp.ndata, notifyData, lastModified);
Run Code Online (Sandbox Code Playgroud)

  • 我使用VS 2010,必须执行_streams.emplace_back(FlashStream(url,标头,数据,_npp.ndata,notifyData,lastModified));`并且它调用析构函数... (2认同)

Ido*_*dov 0

当你推回时,你正在创建一个临时对象。
他就是它的析构函数所称的那个人。