STL的allocator_traits中静态成员函数的用途是什么?

时间:2015-08-21 09:10:37

标签: c++ c++11 stl allocator

我正在尝试实现一个STL样式的容器类,我对我班级中分配器的使用有疑问:

STL' allocator_traits中静态成员函数的用途是什么?

到现在为止,我认为我应该实例化allocator_type(可能通过某种空基础优化来改善内存占用)。因此,我最终会得到这样的结论:

struct EmptyBaseOpt : allocator_type
{
  EmptyBaseOpt(const allocator_type & a, allocator_type::const_pointer p)
  : allocator_type(a), prefix_ptr(p) { }

  allocator_type::pointer prefix_ptr;
}

EmptyBaseOpt ebo;

然后,我可以通过以下方式使用分配器:

allocator_type & alloc = ebo;
alloc.allocate(100, ebo.prefix_ptr);

另一方面,C ++ 11中的allocator_traits似乎意味着以下用法:

std::allocator_traits<allocator_type>::allocate(100, ebo.prefix_ptr);

我想这个静态allocate成员函数可能会通过其默认构造函数创建allocator_type的临时临时实例。但这导致了以下问题:

  1. 如果allocator_type是有状态分配器,会发生什么?如果我使用allocator_traits中的静态成员函数而不是从allocator_type的实例调用非静态方法,这样的分配器是否能够保持其状态?

  2. 如果我可以直接使用allocator_type中的静态成员函数,我为什么要实例化allocator_traits而烦恼EBO之类的东西?

  3. 如前所述,我的理解是,任何类类模板参数都应该在我的容器类中实例化,以便允许这些参数的有状态版本。这种理解是否正确,它如何适应allocator_traits中的静态成员函数?

2 个答案:

答案 0 :(得分:6)

  

另一方面,C ++ 11中的allocator_traits似乎意味着以下用法:

std::allocator_traits<allocator_type>::allocate(100, ebo.prefix_ptr);

不,你错过了该函数调用最重要的参数:分配器。

  

我想这个静态分配成员函数可能会通过其默认构造函数创建一个临时的临时实例allocator_type。

不,因为你将一个allocator参数传递给函数。

  

如果allocator_type是有状态分配器会发生什么?

它工作正常,因为您将有状态分配器作为参数传递给使用它的函数。

  

如果我可以直接使用allocator_traits中的静态成员函数,为什么我要实例化allocator_type而烦恼EBO这样的东西?

因为你不能使用它们。

  

如前所述,我的理解是,任何类类模板参数都应该在我的容器类中实例化,以便允许这些参数的有状态版本。这种理解是否正确,它如何适应allocator_traits中的静态成员函数?

是的,您的理解是正确的,如果您正确使用它,它与allocator_traits完全吻合。

allocator_traits的要点是为大多数Allocator接口提供合理的默认值。这有两个目的:

  • 首先在C ++ 11中定义一个分配器更简单(你只需要提供value_typeallocatedeallocate,一个用于重新绑定的模板构造函数分配器和operator==以及operator!=)所以现在编写简单的自定义分配器要简单得多。

  • 其次,它允许C ++ 11容器使用仅满足C ++ 03分配器要求的现有分配器。 C ++ 03分配器不定义嵌套成员,例如C ++ 11容器所寻找的propagate_on_container_swap,或者新的可变参数construct(pointer, Args&&...)成员,它允许使用任何参数构造对象,而不仅仅是复制构造(允许emplace工作)。因此,通过在allocator_traits中包含分配器的使用,大多数Allocator接口都具有合理的默认值,因此使用带有std::vector等容器的自定义分配器的现有C ++ 03代码不会突然失败如果使用C ++ 11重新编译,则构建。 std::vector实现仅通过allocator_traits类型使用新成员,因此自定义分配器未更新以提供属于C ++ 11的所有新成员并不重要。分配器要求。

答案 1 :(得分:5)

您似乎错过了Alloc &中所有静态成员函数将allocator_traits作为第一个参数的事实。也就是说,他们使用分配器类型的对象来完成他们的工作。

此策略“仅通过allocator_traits访问分配器”的原因是construct的某些成员提供分配器操作的默认实现(如果分配器类型本身未提供)。这适用于在C ++ 11中添加到分配器要求但在C ++ 03中不存在的所有成员。一个示例是new,如果分配器类型未提供合适的::new函数,则会调用展示位置construct运算符allocator_traits。因此,这些默认值允许为C ++ 03编写的分配器在C ++ 11容器中保持不变。

此外,使用allocator_traits可以提供更多自定义功能。可以为特定的分配器类指定Alloc &,并且可以通过allocator_type参数上的不同调用来实现特征函数。

因此,您对实例化allocator_traits的假设是正确的。区别在于您不应该直接调用其成员函数(因为它们可能不存在),而是通过<!-- Boostrap Help --> <html lang="en"> <head> <title>Example </title> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css"> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap-theme.min.css"> <meta name="viewport" content="width=device-width, initial-scale=1"> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script> <style type="text/css"> p { padding: 50px; font-size: 32px; font-weight: bold; text-align: center; background: #f2f2f2; } #circle { background: #f00; width: 50px; height: 50px; border-radius: 50%; } </style> </head> <body> <div class="container"> <div class="row"> <div class="col-md-12"> <p>Category 1</p> <div id="circle"></div> </div> <div class="col-md-8"> <p>Category 2</p> </div> <div class="col-md-4"> <p>Category 3</p> </div> <div class="col-md-8"> <p>Category 4</p> </div> <div class="col-md-8"> <p>Category 5</p> </div> </div> </div> </body> </html>中的静态访问器。