标签: allocator

为什么 std::vector 没有释放方法?

我发现自己处于这样一种情况,我希望有一个类似于unique_ptrs release()for的情况std::vector<>。例如:

std::vector<int> v(SOME_SIZE);

//.. performing operations on v

int* data = v.release(); // v.size() is now 0 and the ownership of the internal array is released
functionUsingAndInternallyDeletingRowPointer(data);
Run Code Online (Sandbox Code Playgroud)

有什么特殊原因不提供这种可能性吗?std::vector这会对内部实施施加一些限制吗?

或者有一种方法可以实现这一点,而我却尴尬地错过了?

c++ stl vector std allocator

6
推荐指数
2
解决办法
4587
查看次数

C++:无法使用 scoped_allocator_adaptor 传播 polymorphic_allocator

我有 avector<vector<int>>并且希望从a 中获取整个内存(即,外部和内部向量的)memory_resource。这是一个精简的示例,首先是无聊的部分:

#include <boost/container/pmr/memory_resource.hpp>
#include <boost/container/scoped_allocator.hpp>
#include <boost/container/pmr/polymorphic_allocator.hpp>
#include <iostream>
#include <string>
#include <vector>

// Sample memory resource that prints debug information
class MemoryResource : public boost::container::pmr::memory_resource {
  void* do_allocate(std::size_t bytes, std::size_t alignment) {
    std::cout << "Allocate " << bytes << " bytes" << std::endl;
    return malloc(bytes);
  }
  void do_deallocate(void* p, std::size_t bytes, std::size_t alignment) { free(p); }
  bool do_is_equal(const memory_resource& other) const noexcept { return true; }
};
Run Code Online (Sandbox Code Playgroud)

这是我感兴趣的部分:

template <typename T>
using Alloc …
Run Code Online (Sandbox Code Playgroud)

c++ boost allocator c++17 c++pmr

6
推荐指数
1
解决办法
733
查看次数

类型擦除上下文中的 C++ 内存分配(使用分配器)

标准 C++ 库中有许多类可能会分配内存但不接受分配器。其中一些这样做是因为在类型擦除的上下文中分配内存是不可能的。

一个例子是 std::any 有一个构造函数,该构造函数在其设计的某个时刻接受了一个 Allocator 参数,但由于似乎无法实现而被丢弃。我确实对这种情况考虑了一段时间,我想知道阻止其实施的确切问题是什么不能满足标准的哪些要求

假设我们从any. 分配内存很简单:

struct any {

    struct type_interface;

    template <typename T>
    struct type_impl;

    type_interface* value;

    any(T&& value, const Allocator& allocator = Allocator()) {
        using actual_allocator_t
            = std::allocator_traits<Allocator>::rebind_alloc<type_impl<T>>;
        actual_allocator_t actual_allocator;
        // do allocate
        // do construct
        // assign obtained pointer
    }
};
Run Code Online (Sandbox Code Playgroud)

问题显然是我们失去了最初分配对象的分配器type_impl<T>。一个技巧可能是创建一个方法来声明一个静态变量来存储该分配器。

template <typename Allocator>
auto& get_allocator(const Allocator& allocator) {
    using actual_allocator_t = std::allocator_traits<Allocator>::rebind_alloc<type_impl<T>>;
    // static variable: initialized just on the …
Run Code Online (Sandbox Code Playgroud)

c++ memory-management type-erasure allocator c++-standard-library

6
推荐指数
0
解决办法
173
查看次数

分配器实现中提示参数的使用示例

标准分配器可以选择提示作为默认参数https://en.cppreference.com/w/cpp/memory/allocator/allocate

T* allocate( std::size_t n, const void * hint);
Run Code Online (Sandbox Code Playgroud)

暂且不说这在 C++20 中已被正式弃用(这显然并不意味着分配器不能具有提示参数):

您知道hint现有代码或理论代码中标准或非标准分配器实现的良好用途吗?或者说它只是一个普通的历史遗迹?

我试图了解当前的提示是否可以帮助您在拥有多个设备(例如 GPU)时进行分配。

注 1: 我不是问如何在 cpu 或 gpu 中分配内存,我试图查看hint在内部使用此参数的良好或经过验证的代码,大概是效率和特定类型的内存。即使它是一些奇异的系统。

注2: 我不是问如何/如果/什么作为提示参数传递(即“仅传递容器的当前指针”),就像链接的问题中一样。我是从实现自定义分配器的人的角度来问的。

c++ hint allocator

6
推荐指数
1
解决办法
406
查看次数

分配器的分配和构造是否通过 [basic.life]p8 明确定义?

cppreference 的 std::allocator 示例包含以下代码(为简单起见缩短):

// default allocator for ints
std::allocator<int> alloc1;

using traits_t1 = std::allocator_traits<decltype(alloc1)>; // The matching trait
p1 = traits_t1::allocate(alloc1, 1);
traits_t1::construct(alloc1, p1, 7);  // construct the int
std::cout << *p1 << '\n';
Run Code Online (Sandbox Code Playgroud)

就分配器而言,相当简单。然而,标准保证中的哪些措辞p1实际上指向新对象呢?

根据std::allocate和[allocator.members]上的 cppreference 文档,默认分配器的函数allocate()

在存储中创建 T[n] 类型的数组并开始其生存期,但不开始其任何元素的生存期。

并返回

[指针] 指向 n 个 T 类型对象的数组的第一个元素,该数组的元素尚未构造。

Afaik,数组创建措辞已添加到标准中,以便指针上的指针算术有效。无论如何,这意味着返回的指针指向 的第一个元素,T[]并且该第一个元素的生命周期尚未开始

construct()然后在此位置创建一个对象,但是,它不会返回指向该对象的指针。我们拥有的唯一指针仍然是返回的指针allocate

通常,当一个对象被放置在过期对象的位置时,它可以在[basic.life]p8中规定的条件下“透明地替换”旧对象:(强调我的)

如果在一个对象的生命周期结束之后,在该对象所占用的存储被重用或释放之前,在原对象所占用的存储位置上创建了一个新对象,一个指向原对象的指针[... ] 将自动引用新对象,并且一旦新对象的生命周期开始[...]

该数组元素的生命周期从未开始,因此它不可能结束,因此这不适用。那么如何才能保证对新构造的对象的访问是明确定义的呢?每次通话后都std::launder应该使用吗construct …

c++ memory-management allocator language-lawyer

6
推荐指数
1
解决办法
87
查看次数

分配器类型参数的C++设计模式

当将类型传递给要作为分配器的类时,C++ 03标准库使用简单的模板类型参数.这是可能的,因为模板在C++中的工作方式.但是,它并不是非常简单,您可能不知道类型定义应该是什么样子 - 特别是在非标准类型的情况下.

我认为使用适配器类instread可能是个好主意.我已经创建了一个示例来向您展示我的意思:

#ifndef HPP_ALLOCATOR_ADAPTOR_INCLUDED
#define HPP_ALLOCATOR_ADAPTOR_INCLUDED


#include <memory>


template<typename T>
struct allocator_traits;

template<typename T, class allocator_type = std::allocator<T>>
class allocator_adaptor;


template<>
struct allocator_traits<void>
{
    typedef std::allocator<void>::const_pointer const_pointer;
    typedef std::allocator<void>::pointer       pointer;
    typedef std::allocator<void>::value_type    value_type;
};

template<typename T>
struct allocator_traits
{
    typedef typename std::allocator<T>::const_pointer   const_pointer;
    typedef typename std::allocator<T>::const_reference const_reference;
    typedef typename std::allocator<T>::difference_type difference_type;
    typedef typename std::allocator<T>::pointer         pointer;
    typedef typename std::allocator<T>::reference       reference;
    typedef typename std::allocator<T>::size_type       size_type;
    typedef typename std::allocator<T>::value_type      value_type;
};


template<class allocator_type>
class allocator_adaptor<void, allocator_type>
    : public allocator_traits<void>
{ …
Run Code Online (Sandbox Code Playgroud)

c++ design-patterns stl allocator

5
推荐指数
1
解决办法
1595
查看次数

为什么std :: allocator <> :: deallocate()有一个未使用的size_type参数?

使用时std::allocator,该deallocate函数需要一个pointer参数和一个size_type参数(std::allocator<>::deallocate(std::allocator<>::pointer p, std::allocator<>::size_type).但是,size_type不使用,也不是可选的.那么为什么会出现?它真的让我困惑,因为它应该是可选的,甚至不是那里,因为它没有在函数中使用.

编辑:MSVC的allocator实现deallocate

void deallocate(pointer _Ptr, size_type)
    {   // deallocate object at _Ptr, ignore size
    ::operator delete(_Ptr);
    }
Run Code Online (Sandbox Code Playgroud)

c++ parameters allocator

5
推荐指数
1
解决办法
415
查看次数

C++中的分配器用法(STL树)

我最近一直试图理解c ++分配器是如何工作的,而且我一直在寻找STL库使用的红黑树的实现,std::set或者std::map有些东西是我无法得到的.到处走走.

首先要做的是将分配器从容器必须存储_Val的类型 - 转换为树使用的节点类型_Rb_tree_node<_Val>- 使用重新绑定模板:

typedef typename __gnu_cxx::__alloc_traits<_Alloc>::template
    rebind<_Rb_tree_node<_Val> >::other _Node_allocator;

typedef __gnu_cxx::__alloc_traits<_Node_allocator> _Alloc_traits;
Run Code Online (Sandbox Code Playgroud)

我可以解决这个问题.

现在,当插入一个元素并且需要创建一个新节点时,它的作用就是这个

_Node_type __node = _Alloc_traits::allocate(_M_get_Node_allocator(), 1);
Run Code Online (Sandbox Code Playgroud)

我假设为单个节点分配空间.但是它就是这样做的

::new(__node) _Rb_tree_node<_Val>;
Run Code Online (Sandbox Code Playgroud)

我真的不知道它做了什么,因为__node已经分配了空间.但在此之后它也会这样做

_Alloc_traits::construct(_M_get_Node_allocator(), __node->_M_valptr(), ...);
Run Code Online (Sandbox Code Playgroud)

这让我更加困惑,因为它应该构建一个节点(是节点分配器),但是它传递了__node->_M_valptr()类型的指针_Val*.

如果有人能够解释这一点,我将非常感激.

c++ stl allocator c++11

5
推荐指数
1
解决办法
775
查看次数

如何将带有自定义分配器的std :: vector传递给期望使用std :: allocator的函数?

我正在使用外部库(pcl),所以我需要一个不会改变现有函数原型的解决方案.

我正在使用的一个功能生成一个std::vector<int, Eigen::aligned_allocator<int>>.我想要接下来调用的函数需要a const boost::shared_ptr<std::vector<int, std::allocator<int>>>.我不想复制元素,因为它是我代码中已经很慢的关键部分.如果不是因为分配器不匹配,我只需执行以下操作即可绕过shared_ptr要求:

// code that generates std::vector<int, Eigen::aligned_allocator<int>> source
boost::shared_ptr<std::vector<int>> indices(new std::vector<int>);
indices->swap(source);
// use indices as intended
Run Code Online (Sandbox Code Playgroud)

这不能使用MSVC编译器进行编译,因为它无法在这两种向量类型之间进行转换.到目前为止,我所想到的唯一不会复制内容的解决方案是:

// code that generates std::vector<int, Eigen::aligned_allocator<int>> source
boost::shared_ptr<std::vector<int>> indices(new std::vector<int>);
indices->swap(reinterpret_cast<std::vector<int>&>(source));
// use indices as intended
indices->swap(reinterpret_cast<std::vector<int>&>(pcout.points));
Run Code Online (Sandbox Code Playgroud)

注意我需要如何使用索引作为const shared_ptr.我相信分配器不会在交换操作中发挥作用.int也应该不需要对齐任何填充,因为它们已经是32位大小.std :: allocator版本应该能够从对齐版本中读取,因为它只能分配std :: allocator可能已经使用过的内存地址.最后,我换回,因为如果尝试删除未对齐的保留空间,则对齐的分配器可能会崩溃.

我尝试了它并没有崩溃,但这并不是说服我确实它是正确的.安全吗?如果没有,如果对编译器做出某些合理的假设,它是否有条件安全?有没有更明显影响性能的更安全的替代方案?

请不要回复"描述您的代码","不值得"或类似的答案.即使它们适用于此,理论上也存在复制不是可行解决方案的情况,并且该线程应该解决这个问题.

类似的问题是谈论以清晰的方式复制数据,如评论中所阐明的那样.

编辑:似乎尽管Eigen :: aligned_allocator设计用于16位对齐,但没有额外的填充添加到整数.比较列表中第一个和最后一个元素的地址给出了元素数量和sizeof(int)的大小.这意味着int以一种应该与std :: allocator版本兼容的方式存储.我希望我今天晚些时候或在未来几天有时间做一个更完整的测试.

c++ boost vector allocator

5
推荐指数
1
解决办法
1207
查看次数

C ++分配器可以是最终的吗?

分配器要求cppreference页没有说分配器必须是可继承的,即没有说分配器一定不能是最终的。

但是,在许多库中,分配器是私有继承的,以利用无状态分配器的空基类优化。例如:

template <typename T, typename A = std::allocator<T>>
class Dummy_vector :private A {
    // ...
    A get_alloc() const
    {
        return static_cast<A>(*this);
    }
    // ...
};
Run Code Online (Sandbox Code Playgroud)

如果A是最终的,则该实现会中断。

一个可以分配器是最终的?我错过了什么?还是应该为最终分配器包括特殊代码?

(注意:通过“最终分配器的特殊代码”,我的意思是这样的:

template <
    typename T,
    typename A = std::allocator<T>,
    bool = std::is_final<A>
>
class Dummy_vector :private A {
    // version for nonfinal allocators
    // ...
    A get_alloc() const
    {
        return static_cast<A>(*this);
    }
    // ...
};

template …
Run Code Online (Sandbox Code Playgroud)

c++ inheritance memory-management final allocator

5
推荐指数
1
解决办法
137
查看次数