Boost C++ 库

世界上最受推崇和设计最精良的 C++ 库项目之一。 Herb SutterAndrei AlexandrescuC++ Coding Standards

Boost 指针容器库 - Boost C++ 函数库

Boost 指针容器库

作者 Thorsten Ottosen
联系方式 nesotto@cs.aau.dktottosen@dezide.com
组织奥尔堡大学计算机科学系Dezide Aps
日期 2007 年 10 月 27 日
版权 Thorsten Ottosen 2004-2007。使用、修改和分发受 Boost 软件许可证 1.0 版(参见 LICENSE_1_0.txt)的约束。

概述

Boost.Pointer Container 提供了一种以异常安全且开销最小的方式来持有堆分配对象的容器。该库的目标尤其在于通过建立一套标准的类、方法和设计来处理面向对象(OO)的特定问题,从而简化 C++ 中的面向对象编程。

动机

每当程序员想要一个指向堆分配对象的指针容器时,通常只有一种异常安全的方法:创建一个智能指针容器,如 boost::shared_ptr。如果存在以下情况,此方法将不是最优的:

  1. 存储的对象不是共享的,而是独占的,或者
  1. 智能指针所隐含的开销不合适

因此,本库提供了类似标准的容器,用于存储堆分配或克隆的对象(或者在映射容器的情况下,映射的对象必须是堆分配或克隆的对象)。对于每个标准容器,都有一个指针容器的等价物,它以异常安全的方式接管对象的所有权。在这方面,本库旨在解决所谓的多态类问题

指针容器的优点是:

  1. 异常安全的指针存储和操作。
  1. 与使用指针容器相比,命名更方便。
  1. 可用于既不是 Assignable 也不是 Copy Constructible 的类型。
  1. 没有内存开销,因为智能指针容器可能会产生(参见 [11][12])。
  1. 通常比使用智能指针容器更快(参见 [11][12])。
  1. 接口略有改变,更侧重于指针领域,而不是依赖于普通的基于值的接口。例如,现在可以执行pop_back()返回已删除的元素。
  1. 传播 constness,使得用户无法通过以下方式修改对象const_iterator.
  1. 通过 the Clonable concept 内置支持深拷贝语义

缺点是:

  1. boost::shared_ptr 等智能指针容器相比不够灵活。

当你确实需要共享语义时,本库就不适合了。

从 Boost v. 升级1.33.*

如果您从这些 Boost 版本之一升级,那么有一个主要的接口更改:map 迭代器现在模仿来自std::map的迭代器。以前您可能写过

for( boost::ptr_map<std::string,T>::iterator i = m.begin(), e = m.end();
     i != e; ++i )
{
  std::cout << "key:" << i.key();
  std::cout << "value:" << *i;
  i->foo(); // call T::foo()
}

而现在需要转换为

for( boost::ptr_map<std::string,T>::iterator i = m.begin(), e = m.end();
     i != e; ++i )
{
  std::cout << "key:" << i->first;
  std::cout << "value:" << *i->second;
  i->second->foo(); // call T::foo()
}

除了上述更改之外,本库现在还引入了

  • std::auto_ptr<T>重载

    std::auto_ptr<T> p( new T );
    container.push_back( p );
    
  • 派生到基类的转换您可以使用:

    boost::ptr_vector<Base>  vec;
    boost::ptr_list<Derived> list;
    ...
    vec.transfer( vec.begin(), list ); // now ok
    

另外请注意,Boost.Assign 为指针容器提供了更好的支持。

从 Boost v. 升级1.34.*

现在,由于 Sebastian Ramacher 的贡献,序列化已成为可选功能。您只需包含<boost/ptr_container/serialize.hpp>或者可能只包含更专业的头文件之一。

所有容器现在都支持复制构造和赋值。因此,您现在可以执行例如

boost::ptr_vector<Derived> derived = ...;
boost::ptr_vector<Base>    base( derived );
base = derived;

如示例所示,也允许派生到基类的转换。

添加了一些通用函数

VoidPtrContainer&       base();
const VoidPtrContainer& base() const;

这些允许直接访问包装的容器,这有时在您想提供额外功能时是需要的。

为序列添加了一些新函数

void resize( size_type size );
void resize( size_type size, T* to_clone );

ptr_vector<T>有一些新的辅助函数,可以更好地与 C 数组集成。

void transfer( iterator before, T** from, size_type size, bool delete_from = true );
T**  c_array();

最后,您现在也可以“复制”和“赋值”一个auto_type指针,通过调用move():

boost::ptr_vector<T>::auto_type move_ptr = ...;
return boost::ptr_container::move( move_ptr );

从 Boost v. 升级1.35.*

本库相当稳定,但已支持了一些新容器:

  • boost::ptr_unordered_set<T>in<boost/ptr_container/ptr_unordered_set.hpp>
  • boost::ptr_unordered_map<Key,T>in<boost/ptr_container/ptr_unordered_map.hpp>
  • boost::ptr_circular_buffer<T>in<boost/ptr_container/ptr_circular_buffer.hpp>

这些类还没有文档,但它们几乎与boost::ptr_set<T>, boost::ptr_map<Key,T>andboost::ptr_array<T,N>分别相同。底层容器来自两个 Boost 库:

此外,还添加了插入迭代器

从 Boost v. 升级1.66.*

从 Boost v. 开始1.67.0,Boost.Pointer Container 将使用 Boost.Config 来有条件地提供std::unique_ptr接口,这些接口除了使用`std::auto_ptr`之外,或者代替使用

compatible-smart-ptr<T>

。详细信息请参见Compatible Smart Pointer 页面,该页面还解释了本文档中用于表示此类条件接口的约定。

对于 C++98/03 用户,此更改没有可观察到的影响。

对于 C++11/14 用户,对已使用以前版本的 Boost.Pointer Container 的现有代码没有影响,但现在所有接受`std::auto_ptr`参数的函数重载都伴随着一个接受std::unique_ptr参数的重载。在返回类型的情况下,`std::auto_ptr`始终使用。但请注意,直到 C++17,都可以隐式地从构造。因此,用户可以自由地现代化其代码,将任何显式提及std::auto_ptr<T>替换为`std::auto_ptr`带有std::unique_ptr。此更改几乎是一个搜索和替换的转换,因为有可能某些代码依赖于`std::auto_ptr`是可复制的。但这种情况将导致编译时错误,应易于修复。

虽然`std::auto_ptr`在 ISO C++17 中已被正式删除,但某些编译器或标准库供应商选择保留它以实现向后兼容。对于不属于这种情况的编译器和标准库,使用 Boost v. 进行 C++17 编译的代码1.66.*或更早版本是不可能的。此情况在 Boost v. 中已修复。1.67.0.

未来发展

有迹象表明void*实现相对于T*基于的实现略有性能开销。此外,T*基于的实现类型更安全,与算法一起使用起来也更容易。因此,我预计将转向T*基于的实现。

此外,克隆分配器可能允许有状态。此设计需要一些思考,如果您有关于此的良好想法和用例,请随时与我联系。

此外,Boost.Interprocess 的支持也在计划中。

有一些请求要求实现boost::ptr_multi_index_container<T,...>。我研究了其难度,发现它确实很困难,尽管并非不可能。但我没有资源在未来几年内实现这个庞然大物,所以如果有人确实需要这个容器,我建议他们私下与我讨论如何实现。

致谢

以下人员提供了极大的帮助:

  • Bjørn D. Rasmussen,无意中激励我开始这个库。
  • Pavel Vozenilek,让我创建适配器。
  • David Abrahams,提供了indirect_fun设计。
  • Pavol Droba,担任评审经理。
  • Ross Boylan,在库成为 Boost 的一部分之前就真实地试用过原型。
  • Felipe Magno de Almeida,在库成为 Boost 的一部分之前就通过在生产代码中使用该库提供了反馈。
  • Jonathan Turkanis,提供了他的move_ptr框架,该框架在内部使用。
  • Stefan Slapeta 和 Howard Hinnant,提供 Metrowerks 支持。
  • Russell Hind,在 Borland 兼容性方面提供帮助。
  • Jonathan Wakely,在 GCC 兼容性和错误修复方面提供了极大的帮助。
  • Pavel Chikulaev,提供评论和错误修复。
  • Andreas Hommel,修复了棘手的 Metrowerks 错误。
  • Charles Brockman,对文档提供了许多评论。
  • Sebastian Ramacher,实现了可选的序列化支持。

参考文献

[1]Matt Austern:“The Standard Librarian: Containers of Pointers”,C/C++ Users Journal Experts Forum。
[2]Bjarne Stroustrup,“The C++ Programming Language”,附录 E:“Standard-Library Exception Safety”
[3]Herb Sutter,“Exceptional C++”。
[4]Herb Sutter,“More Exceptional C++”。
[5]Kevlin Henney:“From Mechanism to Method: The Safe Stacking of Cats”,C++ Experts Forum,2002 年 2 月。
[6]我所看到的一些早期指针容器的尝试包括相当有趣的 NTLpointainer。截至本文撰写之时,这两个库都不是异常安全的,可能会发生内存泄漏。
[7]国际标准,编程语言 — C++,ISO/IEC 14882,1998。特别是参见第 23 节。
[8]C++ 标准库已关闭问题列表(修订版 27),第 218 项,算法不使用二元谓词对象进行默认比较
[9]C++ 标准库活动问题列表(修订版 27),第 226 项,用户提供的命名空间 std 函数模板的特化或重载
[10]Harald Nowak,“A remove_if for vector”,C/C++ Users Journal,2001 年 7 月。
[11]12 Boost 智能指针计时
[12]12 NTL:数组与 std::vector 和 boost::shared_ptr
[13]Kevlin Henney,“Null Object”,2002 年。

版权Thorsten Ottosen 2004-2006。