jjzjj

c++ - 选择什么标准容器(如果有)?

coder 2024-02-02 原文

我需要一些内存管理,希望我可以将其基于一些 std容器。我的要求是:

  1. 元素只有一个默认构造函数(没有复制,没有移动,没有别的)
  2. 容器可以通过一小块连续的元素扩展(在后面)
  3. 我什至可以粗略地知道我总共需要多少元素,甚至可以随时知道最终需要多少元素。不过,这些都是估计值。
  4. 我真的不需要迭代器,但获取元素运行编号的方法会很方便。

所以,我需要一些可以通过添加 block 来扩展的东西,比如 std::deque .但是用std::deque ,我不能保证扩展,比如说,8 个元素,给我一个连续的 block 。和 std::deque没有 capacity所以我不能从 std::deque 中“适应” .

这意味着我必须自己编写,对吗? (注意:我不想知道如何编写自己的代码,但只有在我不得不这样做的情况下才)。

编辑澄清:只有在每次扩展中获得的元素 block 必须是连续的,而不是整个容器——这显然与其他要求相矛盾。

为 jalf 编辑 那么这是做什么用的:用于“排序”3D 点的空间八叉树。树节点指的是立方体单元,并形成一个链接结构,父节点和子节点使用指针链接。兄弟节点没有链接,但在内存中相邻。节点总数事先未知(因为每个最终节点的点数>1),但可以获得估计值。在树构建过程中,在划分一个非最终节点时,必须获得最多 8 个新节点的连续 block ,然后将其链接到树中。移动或复制这些节点会使指向它们的任何现有链接(指针)失效。

另一个编辑 只是为了澄清一些讨论。任何基于 std::vector<T> 的设计不得使用 resize()和/或 reserve() .两者都需要复制或移动 T 的构造函数在某些条件下。即使从未在这些条件下调用,代码也不会编译。

最佳答案

只要一抓,std::vector 就是为您准备的。

它是完全连续的,而不仅仅是在 block 中,并且可以扩展,保持连续(第 2 点)。扩展可能意味着重新分配(因此使先前获得的指针/迭代器失效,并且移动),但如果您提前知道总大小(第 3 点),则可以 reserve() 这样就不会发生重新分配。

给定 vector v的迭代器i,你可以通过i - v.begin()获得一个流水号(位置);类似地,通过 p - &v[0](第 4 点)给定一个指向元素的指针 p

重点是 1. 有 emplace_back(),但出于异常安全相关的原因,std::vector 仍然尝试在某处临时构造元素,然后他们移动到他们的永久位置。

假设你有这个类

struct A
{
    A() { }
    A(A&&) = delete;
    A(const A&) = delete;
};

我可以看到两个解决方法:

  1. 派生另一个默认构造而不是复制/移动构造的类 B:

    struct B : A
    {
        B() : A() { }
        B(B&&) : A() { }
        B(const B&) : A() { }
    };
    
  2. 如果您不能那样做,那么创建一个分配器对象来为您做这件事:

    template<typename T>
    struct allocator : std::allocator<T>
    {
        using std::allocator<T>::allocator;
        using std::allocator<T>::construct;
    
        template<typename U>
        void construct(U* p, U&&) { construct(p); }
    
        template<typename U>
        void construct(U* p, const U&) { construct(p); }
    
        template<typename U>
        struct rebind { using other = allocator<U>; };
    };
    
    template<>
    struct allocator<void> : std::allocator<void> { };
    

这两种情况的使用说明如下 ( live example ):

template<typename C, size_t N = 100>
void test()
{
    C c;
    c.reserve(N);
    for (size_t i = 0; i < N; ++i)
        c.emplace_back();
}

int main ()
{
    test<std::vector<B> >();
    test<std::vector<A, allocator <A> > >();
}

请记住,通过这种方式仍然有 A 的实例被构建然后被丢弃。这是使用 std::vector 的不幸后果。如果 A 足够小并且其默认构造没有任何奇怪的副作用,那么这应该不是问题。

如果您仍然需要在初始 reserve() 之外进行扩展,那么我建议将此类 vector 的容器用作 block 。如果您仍想将此元容器视为具有自己的迭代器的单个容器,那么相关的是我自己的 join view及其 iterator只是一个想法,但这仍然是非常实验性的。我敢打赌 Boost 中也有用于此目的的东西,但我不是很熟悉。

关于c++ - 选择什么标准容器(如果有)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23030082/

有关c++ - 选择什么标准容器(如果有)?的更多相关文章

  1. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  2. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  3. ruby - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

    我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

  4. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  5. ruby - 为什么 4.1%2 使用 Ruby 返回 0.0999999999999996?但是 4.2%2==0.2 - 2

    为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返

  6. ruby-on-rails - 如果为空或不验证数值,则使属性默认为 0 - 2

    我希望我的UserPrice模型的属性在它们为空或不验证数值时默认为0。这些属性是tax_rate、shipping_cost和price。classCreateUserPrices8,:scale=>2t.decimal:tax_rate,:precision=>8,:scale=>2t.decimal:shipping_cost,:precision=>8,:scale=>2endendend起初,我将所有3列的:default=>0放在表格中,但我不想要这样,因为它已经填充了字段,我想使用占位符。这是我的UserPrice模型:classUserPrice回答before_val

  7. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  8. ruby - ruby 中的 TOPLEVEL_BINDING 是什么? - 2

    它不等于主线程的binding,这个toplevel作用域是什么?此作用域与主线程中的binding有何不同?>ruby-e'putsTOPLEVEL_BINDING===binding'false 最佳答案 事实是,TOPLEVEL_BINDING始终引用Binding的预定义全局实例,而Kernel#binding创建的新实例>Binding每次封装当前执行上下文。在顶层,它们都包含相同的绑定(bind),但它们不是同一个对象,您无法使用==或===测试它们的绑定(bind)相等性。putsTOPLEVEL_BINDINGput

  9. ruby - Infinity 和 NaN 的类型是什么? - 2

    我可以得到Infinity和NaNn=9.0/0#=>Infinityn.class#=>Floatm=0/0.0#=>NaNm.class#=>Float但是当我想直接访问Infinity或NaN时:Infinity#=>uninitializedconstantInfinity(NameError)NaN#=>uninitializedconstantNaN(NameError)什么是Infinity和NaN?它们是对象、关键字还是其他东西? 最佳答案 您看到打印为Infinity和NaN的只是Float类的两个特殊实例的字符串

  10. ruby-on-rails - 如果 Object::try 被发送到一个 nil 对象,为什么它会起作用? - 2

    如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象

随机推荐