过去 6 个月我一直在使用 Qt,但我仍在努力理解隐式共享类的概念。我有以下问题:
感谢大家的所有回答..我想到了关于这个主题的另一点是堆栈对象指向堆分配的共享数据..这是图表...
对此有何看法???...引用计数到底是什么?当对象引用公共(public)共享数据时,它是一种计数器吗?反之亦然?
最佳答案
想象一下。你正在使用 C++03 并且你写:
string a("hello");
string b = a;
此时你有两个字符串对象 a 和 b 并且每个都有自己的缓冲区来存储一个字符数组。即使缓冲区的内容完全相同,a 和 b 仍然有自己的“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
}
因此资源使用最大化,复制最小化。 a 和 b 使用相同的 SharedData(也称为 int 3)。 . 4 并未从 a 复制到 b,它们只是共享相同的数据。一个 int 没什么大不了的,但想象一下如果 SharedData 包含一些大字符串或任何其他更复杂的数据结构。只复制一个指针比复制几十个字节要快得多。当您真的不需要拷贝时,它还可以节省大量内存。
什么是写时复制?
回想上面我在执行 b[0]='M' 时所说的话。那是写时复制。 b 和 a 共享同一个字符数组。但是 b 需要修改字符串。它不能直接这样做,因为那样也会修改 a 的字符串。所以 b 必须创建自己的 char 数组拷贝才能更改它。因为它只需要在修改数组时创建拷贝,所以它被称为写时复制。
关于c++ - 什么是隐式共享类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12233754/
类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
我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co
我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%
我主要使用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
为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返
我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server
我正在编写一个gem,我必须在其中fork两个启动两个webrick服务器的进程。我想通过基类的类方法启动这个服务器,因为应该只有这两个服务器在运行,而不是多个。在运行时,我想调用这两个服务器上的一些方法来更改变量。我的问题是,我无法通过基类的类方法访问fork的实例变量。此外,我不能在我的基类中使用线程,因为在幕后我正在使用另一个不是线程安全的库。所以我必须将每个服务器派生到它自己的进程。我用类变量试过了,比如@@server。但是当我试图通过基类访问这个变量时,它是nil。我读到在Ruby中不可能在分支之间共享类变量,对吗?那么,还有其他解决办法吗?我考虑过使用单例,但我不确定这是
它不等于主线程的binding,这个toplevel作用域是什么?此作用域与主线程中的binding有何不同?>ruby-e'putsTOPLEVEL_BINDING===binding'false 最佳答案 事实是,TOPLEVEL_BINDING始终引用Binding的预定义全局实例,而Kernel#binding创建的新实例>Binding每次封装当前执行上下文。在顶层,它们都包含相同的绑定(bind),但它们不是同一个对象,您无法使用==或===测试它们的绑定(bind)相等性。putsTOPLEVEL_BINDINGput
我可以得到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类的两个特殊实例的字符串
如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象