C++ 如何在现代C++;

C++ 如何在现代C++;,c++,c++11,typetraits,c++17,allocator,C++,C++11,Typetraits,C++17,Allocator,从我在书中读到的内容来看,分配器的大多数功能现在都将被弃用。问题是,在新代码中应该如何使用分配器?现在“正确”的方法是什么 从我在文档中推断,construct是分配器特性的一部分,而不是分配器本身 我正在构建一个定制容器,这是一个非常简单的构造函数版本,这是新设计的一个好用法吗 container::container(std::size_t size, T const& value, Allocator const& allocator) : allocator_(alloc

从我在书中读到的内容来看,分配器的大多数功能现在都将被弃用。问题是,在新代码中应该如何使用分配器?现在“正确”的方法是什么

从我在文档中推断,
construct
是分配器特性的一部分,而不是分配器本身

我正在构建一个定制容器,这是一个非常简单的构造函数版本,这是新设计的一个好用法吗

container::container(std::size_t size, T const& value, Allocator const& allocator) : allocator_(allocator){
    data_ = std::allocator_traits<Alloc>::allocate(allocator_, size);
    for(auto ptr = data_; ptr != data_ + size; ++ptr){
        std::allocator_traits<Allocator>::construct(allocator_, ptr, value)
    }
}

是的,当前的方法是通过
std::allocator\u traits
。您将能够通过这种方式支持“最小分配器接口”

有些需求是可选的:模板
std::allocator_traits
为所有可选需求提供默认实现,所有标准库容器和其他支持分配器的类通过
std::allocator_traits
访问分配器,而不是直接访问分配器

如果您观察
std::allocator_traits
成员函数和typedef,您将看到它们检测到适当函数/类型的存在,并在可能的情况下通过它们进行调度

如果您已经在使用
std::allocator\u traits
,则弃用和将来可能的删除将不会改变任何内容,因为它只适用于
std::allocator
及其成员函数/typedef

现在,如果你问我,for循环没有什么错,使用
std::for_each
不会给你带来任何好处。有几个
未初始化的*
函数,但它们直接使用placement new。如果您真的在意,您可以将此代码提取到一个单独的
construct\u range
函数中


还有一个异常安全问题——如果有一个构造函数抛出,您需要销毁早期的元素,以满足强异常保证并释放内存(构造函数抛出时不会调用析构函数)

这是自C++11以来正确的方法(为循环条件对中断的
进行模化)。C++17只改变了弃用一组无论如何都不应该调用的函数。此外,没有
construct\n
“从我读到的内容来看,分配器的大多数功能现在将被剥离并弃用。”更正:这不是“弃用”的内容意思是。弃用并不意味着“剥离”。它意味着“在以后的版本中可以删除”。它还没有到任何地方。@t.C.,我更正了代码(循环)。编写循环的正确方法是什么(例如,可以给出一个执行策略,
std::for_each
?)@Nicolabolas,谢谢。是的,我想我的意思是,新的正确方法是什么。我正在寻找替换原始循环的方法,以便将来可以传递执行策略。您将如何使用
unitialized.*
(哪一个?)@alfC替换原始循环,如答案中所述,
未初始化的*
(这里我们正在做
未初始化的\u fill\n
正在做的事情)函数直接使用placement new,而不是std::allocator_traits::construct
,因此它们不会分派到自定义构造函数。现在,如果您计划使用执行策略,这实际上可能是一件好事,因为您无法确定这些分配器的成员函数是否线程安全,以及它们是否ow exceptions.ok,所以这里不应该使用
unitialized.*
,因为他们对分配器一无所知。这迫使我使用
std::for_each
,但这让我很困惑,因为我会使用
std::for_each([policy,]data_u,data_u+size,[&](auto&e){std::allocator\u traits::construct(allocator_u,&e,value)})
听起来有点可疑。你所说的执行策略非常有趣,因为这意味着执行策略应该依赖于分配器,实际上它是一种特性。最后,我认为应该是
分配器特性
提供了
构造
函数。
    data_ = std::allocator_traits<Allocator>::allocate(allocator_, size);
    std::for_each([policy? deduced from allocator?,] 
        boost::make_counting_iterator(data_),
        boost::make_counting_iterator(data_ + size), 
        [&](auto ptr){std::allocator_traits<Allocator>::construct(allocator_, ptr, value);}
    );