草庐IT

c++ - 什么是隐式共享类?

coder 2024-01-31 原文

过去 6 个月我一直在使用 Qt,但我仍在努力理解隐式共享类的概念。我有以下问题:

  1. 什么是隐式共享类,它们是如何工作的?
  2. Trolltech 的 Qt 网站称它最大限度地利用了资源并最大限度地减少了复制。请向我解释这是怎么发生的。
  3. 任何人都可以举出任何例子来更好地理解吗?也欢迎链接到任何解释这个概念的网站,无论是否有示例。

感谢大家的所有回答..我想到了关于这个主题的另一点是堆栈对象指向堆分配的共享数据..这是图表...

对此有何看法???...引用计数到底是什么?当对象引用公共(public)共享数据时,它是一种计数器吗?反之亦然?

最佳答案

想象一下。你正在使用 C++03 并且你写:

string a("hello");
string b = a; 

此时你有两个字符串对象 ab 并且每个都有自己的缓冲区来存储一个字符数组。即使缓冲区的内容完全相同,ab 仍然有自己的“hello”拷贝。这是一种内存浪费。如果他们共享缓冲区,您将不得不使用一个字符数组来存储两个字符串的“hello world”。

现在使用 QString 有点不同:

QString a("Hello");
QString b = a;

在这种情况下,只有 a 创建了一个 char 数组来存储“hello”。 b 不会创建自己的 char 数组,而是简单地指向 a 的 char 数组。这样可以节省内存。

现在如果你做 b[0]='M',id est,你修改 b,然后 b 创建它自己的字符数组,复制 a 数组的内容,然后修改它自己的数组。

在 Java 中,字符串是不可变的对象。换句话说,Java 没有在 String 类上提供任何方法来修改其内容。这样做是为了始终可以共享此类数据。

补充别人提到的东西:

我怎么知道我可以释放字符数组?
这就是“引用计数”的用途。当一个对象被创建并设置为指向 char 数组时,它的引用计数将增加 1,因此它知道有多少对象仍在使用它。当指向它的对象被销毁时,引用计数会减少。当计数器归零时,char 数组知道没有人在使用它,因此它可以被释放。

这是引用计数的一个非常粗略的实现。无论如何,我不打算准确或正确。我忽略了在 C++ 中实现复制构造函数和赋值运算符的正确方法。我无法检查实现是否有效。认为它是一种有点像 C++ 的算法描述。我只是想教这个概念。但是想象一下你有这些类:

class SharedData{
  private:
    int refcount;
    int data;

  public:
    SharedData(int _data){data=_data;refcount=1;}
    void incRef(){refcount++;}
    void decRef(){--refcount; if(refCount==0) delete this;}
};

class Data{
       SharedData* shared;
    public:
        Data(int i){shared = new Data(i);}
        Data(const Data& data){shared = data.shared; shared->incRef();}
        const Data& operator=(const Data& data){if(shared!=data.shared){
                                       shared->decRef();
                                       shared = data.shared;
                                       shared->incRef();}
        }
        ~Data(){shared->decRef();}
};

Data 的两个对象可以共享同一个 SharedData 对象,所以:

void someFunction() {
    Data a(3) //Creates a SharedData instance and set refcount to 1
    if (expression) {
       Data b = a; //b points to the same SharedData than a. refcount is 2
       b = Data(4);// b points to  diferent SharedData. refcount of SharedData of a is decremented to 1 and b's SharedData has refcount 1
       //destructor of b is called. Because shared data of b has now refcount == 0, the sharedData is freed;
    }
    //destructor of a is called, refcount is decremented again
    // because it is zero SharedData is freed
}

因此资源使用最大化,复制最小化。 ab 使用相同的 SharedData(也称为 int 3)。 . 4 并未从 a 复制到 b,它们只是共享相同的数据。一个 int 没什么大不了的,但想象一下如果 SharedData 包含一些大字符串或任何其他更复杂的数据结构。只复制一个指针比复制几十个字节要快得多。当您真的不需要拷贝时,它还可以节省大量内存。

什么是写时复制?
回想上面我在执行 b[0]='M' 时所说的话。那是写时复制ba 共享同一个字符数组。但是 b 需要修改字符串。它不能直接这样做,因为那样也会修改 a 的字符串。所以 b 必须创建自己的 char 数组拷贝才能更改它。因为它只需要在修改数组时创建拷贝,所以它被称为写时复制

关于c++ - 什么是隐式共享类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12233754/

有关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 - 如何优雅地重启 thin + nginx? - 2

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

  7. ruby - 通过 ruby​​ 进程共享变量 - 2

    我正在编写一个gem,我必须在其中fork两个启动两个webrick服务器的进程。我想通过基类的类方法启动这个服务器,因为应该只有这两个服务器在运行,而不是多个。在运行时,我想调用这两个服务器上的一些方法来更改变量。我的问题是,我无法通过基类的类方法访问fork的实例变量。此外,我不能在我的基类中使用线程,因为在幕后我正在使用另一个不是线程安全的库。所以我必须将每个服务器派生到它自己的进程。我用类变量试过了,比如@@server。但是当我试图通过基类访问这个变量时,它是nil。我读到在Ruby中不可能在分支之间共享类变量,对吗?那么,还有其他解决办法吗?我考虑过使用单例,但我不确定这是

  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中的所有其他对象

随机推荐