std :: get_temporary_buffer和std :: raw_storage_iterator有什么缺点吗?

问题描述 投票:1回答:1

最近,我听说get_temporary_bufferraw_storage_iterator看起来不错。在每个副本中几乎都可以避免初始化N个元素,这可以显着提高性能。

但是我已经使用C ++进行了很多工作,并且在任何地方都没有看到其功能的用法。有什么缺点吗?人们为什么不经常使用它们?为什么我每次要复制时都不使用它们(当然,在新的容器中)?

c++ memory stl iterator allocator
1个回答
0
投票

感谢Tim Song今天(可能不是第一次)向我解释这一点。在此处记录以供后代使用。

raw_storage_iterator的问题是在有异常的情况下无法安全使用。

考虑此非分配器感知的Vector<T>实现:

template<class T>
void Vector<T>::reallocate(int newcap) {
    T *newbuf = (T*)malloc(newcap * sizeof(T));
    Auto( free(newbuf); );
    std::copy(
        buf_, buf_ + size_,
        std::raw_storage_iterator<T*, T>(newbuf)
    );
    std::swap(buf_, newbuf);
    std::swap(cap_, newcap);
    std::destroy(newbuf, newbuf + size_);
}

Autothe Auto macro,又称Auto。当我们点击函数的右花括号时,它可以确保我们正确地ON_SCOPE_EXIT旧分配;并且如果在到达free之前抛出异常,我们将释放new分配。

但是,如果在swap期间引发异常,释放分配不是我们的唯一责任! std::copy可能已经在std::copy中构造了一些T对象。这些newbuf对象本身可以管理资源。如果抛出异常,则在释放T之前,我们必须

调用所有这些T对象的析构函数。否则,我们会发生资源泄漏。

所以,我们应该销毁多少newbuf个对象? ...我们不知道。

T在出现异常的情况下无法安全使用。


raw_storage_iterator(也可以追溯到C ++ 03)没有此问题。

std::uninitialized_copy

std::uninitialized_copy计算成功构造了多少个对象。如果在构造第template<class T> void Vector<T>::reallocate(int newcap) { T *newbuf = (T*)malloc(newcap * sizeof(T)); Auto( free(newbuf); ); std::uninitialized_copy(buf_, buf_ + size_, newbuf); std::swap(buf_, newbuf); std::swap(cap_, newcap); std::destroy(newbuf, newbuf + size_); } 个对象时引发了异常,则std::uninitialized_copy将销毁[ituninitialized_copy)范围内的每个对象,然后再抛出异常。因此,在这种情况下,我们不会发生资源泄漏。

这是删除first而未删除it的根本原因。前者是异常不安全的;后者是异常安全的。


奖金:raw_storage_iteratoruninitialized_copy都不是分配器感知的,这意味着它们不能像raw_storage_iterator那样从字面上构成实现分配器的容器的实现的一部分。每个供应商都必须推出自己的uninitialized_copy以供内部使用。但是据我所知,分配器意识不是std::vector弃用的因素。杀手是异常-不安全的。

© www.soinside.com 2019 - 2024. All rights reserved.